import type { ApolloClient } from '@apollo/client'
import Keys from '@inject/shared/localstorage/keys'
import type { EmailDraftType, IsUnreadType, Resolvers } from '../types'

const resolvers: Resolvers = {
  EmailType: {
    readReceipt: async parent =>
      localStorage.getItem(Keys.getReadReceiptEmailKey(parent.id)) || null,
  },
  EmailThreadType: {
    readReceipt: async parent => {
      const item = localStorage.getItem(
        Keys.getReadReceiptEmailThreadKey(parent.id)
      )
      const readReceipts = JSON.parse(item || '[]') as IsUnreadType[]
      return readReceipts
    },
  },
  ActionLogType: {
    readReceipt: async parent =>
      localStorage.getItem(Keys.getReadReceiptActionLogKey(parent.id)) || null,
  },
  DefinitionChannelType: {
    readReceipt: async parent => {
      const item = localStorage.getItem(
        Keys.getReadReceiptChannelKey(parent.id)
      )
      const readReceipts = JSON.parse(item || '[]') as IsUnreadType[]
      return readReceipts
    },
  },

  Query: {
    async getEmailDraft(_root, variables) {
      const item = localStorage.getItem(
        Keys.getEmailDraftsKey(variables.teamId, variables.instructor)
      )
      const drafts = JSON.parse(item || '[]') as EmailDraftType[]
      const draft = drafts.find(
        draft =>
          (!draft.emailThreadId && !variables.emailThreadId) ||
          draft.emailThreadId === variables.emailThreadId
      )
      return draft
        ? {
            __typename: 'EmailDraftType',
            ...draft,
          }
        : null
    },

    async getEmailDrafts(_root, variables) {
      const item = localStorage.getItem(
        Keys.getEmailDraftsKey(variables.teamId, variables.instructor)
      )
      const drafts = JSON.parse(item || '[]') as EmailDraftType[]
      return drafts
    },
  },

  Mutation: {
    async writeReadReceipt(_root, variables, context) {
      const client = context.client as ApolloClient<Cache>
      const cache = client.cache
      const receipt = new Date().toUTCString()
      localStorage.setItem(
        Keys.getReadReceiptActionLogKey(variables.actionLogId),
        receipt
      )
      cache.modify({
        id: cache.identify({
          __typename: 'ActionLogType',
          id: variables.actionLogId,
        }),
        fields: {
          readReceipt: () => receipt,
        },
      })
      return {
        __typename: 'ReadReceiptType',
        actionLogId: variables.actionLogId,
        readReceipt: receipt,
      }
    },

    async writeReadReceiptEmail(_root, variables, context) {
      const client = context.client as ApolloClient<Cache>
      const cache = client.cache
      const receipt = new Date().toUTCString()
      localStorage.setItem(
        Keys.getReadReceiptEmailKey(variables.emailId),
        receipt
      )
      cache.modify({
        id: cache.identify({
          __typename: 'EmailType',
          id: variables.emailId,
        }),
        fields: {
          readReceipt: () => receipt,
        },
      })
      return {
        __typename: 'EmailReceipt',
        emailId: variables.emailId,
        readReceipt: receipt,
      }
    },

    async setEmailDraft(_root, variables) {
      const item = localStorage.getItem(
        Keys.getEmailDraftsKey(
          variables.emailDraft.teamId,
          variables.emailDraft.instructor
        )
      )
      const drafts = JSON.parse(item || '[]') as EmailDraftType[]
      const existingDraftIndex = drafts.findIndex(
        draft =>
          draft.teamId === variables.emailDraft.teamId &&
          ((!draft.emailThreadId && !variables.emailDraft.emailThreadId) ||
            draft.emailThreadId === variables.emailDraft.emailThreadId) &&
          draft.instructor === variables.emailDraft.instructor
      )
      localStorage.setItem(
        Keys.getEmailDraftsKey(
          variables.emailDraft.teamId,
          variables.emailDraft.instructor
        ),
        JSON.stringify(
          existingDraftIndex === -1
            ? [...drafts, variables.emailDraft]
            : [
                ...drafts.slice(0, existingDraftIndex),
                variables.emailDraft,
                ...drafts.slice(existingDraftIndex + 1),
              ]
        )
      )
      return {
        __typename: 'EmailDraftType',
        ...variables.emailDraft,
      }
    },

    async deleteEmailDraft(_root, variables) {
      const item = localStorage.getItem(
        Keys.getEmailDraftsKey(variables.teamId, variables.instructor)
      )
      const drafts = JSON.parse(item || '[]') as EmailDraftType[]
      const existingDraftIndex = drafts.findIndex(
        draft =>
          draft.teamId === variables.teamId &&
          ((!draft.emailThreadId && !variables.emailThreadId) ||
            draft.emailThreadId === variables.emailThreadId) &&
          draft.instructor === variables.instructor
      )
      if (existingDraftIndex === -1) {
        return { operationDone: false }
      }
      localStorage.setItem(
        Keys.getEmailDraftsKey(variables.teamId, variables.instructor),
        JSON.stringify([
          ...drafts.slice(0, existingDraftIndex),
          ...drafts.slice(existingDraftIndex + 1),
        ])
      )
      return { operationDone: true }
    },

    async setIsUnreadEmailThread(_root, variables, context) {
      const item = localStorage.getItem(
        Keys.getReadReceiptEmailThreadKey(variables.threadId)
      )
      const readReceipts = JSON.parse(item || '[]') as IsUnreadType[]
      const existingReadReceiptIndex = readReceipts.findIndex(
        readReceipt => readReceipt.teamId === variables.teamId
      )

      if (
        existingReadReceiptIndex !== -1 &&
        readReceipts[existingReadReceiptIndex].isUnread === variables.isUnread
      ) {
        return { operationDone: false }
      }

      const newReadReceipts =
        existingReadReceiptIndex === -1
          ? [
              ...readReceipts,
              { teamId: variables.teamId, isUnread: variables.isUnread },
            ]
          : [
              ...readReceipts.slice(0, existingReadReceiptIndex),
              { teamId: variables.teamId, isUnread: variables.isUnread },
              ...readReceipts.slice(existingReadReceiptIndex + 1),
            ]
      localStorage.setItem(
        Keys.getReadReceiptEmailThreadKey(variables.threadId),
        JSON.stringify(newReadReceipts)
      )

      const client = context.client as ApolloClient<Cache>
      const cache = client.cache
      cache.modify({
        id: cache.identify({
          __typename: 'EmailThreadType',
          id: variables.threadId,
        }),
        fields: {
          readReceipt: () => newReadReceipts,
        },
      })

      return { operationDone: true }
    },

    async setIsUnreadChannel(_root, variables, context) {
      const item = localStorage.getItem(
        Keys.getReadReceiptChannelKey(variables.channelId)
      )
      const readReceipts = JSON.parse(item || '[]') as IsUnreadType[]
      const existingReadReceiptIndex = readReceipts.findIndex(
        readReceipt => readReceipt.teamId === variables.teamId
      )

      if (
        existingReadReceiptIndex !== -1 &&
        readReceipts[existingReadReceiptIndex].isUnread === variables.isUnread
      ) {
        return { operationDone: false }
      }

      const newReadReceipts =
        existingReadReceiptIndex === -1
          ? [
              ...readReceipts,
              { teamId: variables.teamId, isUnread: variables.isUnread },
            ]
          : [
              ...readReceipts.slice(0, existingReadReceiptIndex),
              { teamId: variables.teamId, isUnread: variables.isUnread },
              ...readReceipts.slice(existingReadReceiptIndex + 1),
            ]
      localStorage.setItem(
        Keys.getReadReceiptChannelKey(variables.channelId),
        JSON.stringify(newReadReceipts)
      )

      const client = context.client as ApolloClient<Cache>
      const cache = client.cache
      cache.modify({
        id: cache.identify({
          __typename: 'DefinitionChannelType',
          id: variables.channelId,
        }),
        fields: {
          readReceipt: () => newReadReceipts,
        },
      })

      return { operationDone: true }
    },
  },
}

export default resolvers
