'use client'

import { useQuery, useQueryClient, keepPreviousData } from '@tanstack/react-query'
import { apiClient, OfflineError } from '../client'
import { useAuthReady } from '../use-auth-ready'
import { normalizeListPageSize, LIST_PAGE_SIZE } from '@/lib/mail-list-page-size'
import { useIsDemoMail } from '@/lib/demo/demo-mail-context'
import { useDemoMailStore } from '@/lib/demo/demo-mail-store'
import { DEMO_MAIL_ACCOUNT } from '@/lib/demo/demo-mail-api-data'
import type {
  PaginatedResponse,
  ApiMessageSummary,
  ApiMessageFull,
  ApiMailAccount,
  MessageSearchFilter,
} from '../types'
import { isMessageSearchFilterActive } from '@/lib/mail-search/search-filter'

type ApiMessagesPayload = PaginatedResponse<ApiMessageSummary> & {
  messages?: ApiMessageSummary[]
}

/** Backend returns `{ messages, pagination }`; client normalizes to `{ data, pagination }`. */
export function unwrapMessages(
  res: ApiMessagesPayload
): PaginatedResponse<ApiMessageSummary> {
  if (Array.isArray(res.data)) {
    return { data: res.data, pagination: res.pagination }
  }
  const messages = res.messages ?? []
  return {
    data: messages,
    pagination: res.pagination ?? {
      page: 1,
      page_size: messages.length,
      total: messages.length,
    },
  }
}

export const MAIL_MESSAGES_QUERY_ROOT = ['messages'] as const
export const DEMO_MAIL_MESSAGES_QUERY_ROOT = ['demo', 'messages'] as const

export function messagesQueryKey(
  folder: string,
  accountId?: string,
  page?: number,
  pageSize?: number
) {
  return ['messages', folder, accountId, page, pageSize] as const
}

/** Demo list keys are isolated from persisted real-mail `messages` cache (IDB). */
export function messagesListQueryKey(
  folder: string,
  accountId?: string,
  page?: number,
  pageSize?: number,
  isDemo?: boolean,
  demoVersion?: number
) {
  if (isDemo) {
    return [
      'demo',
      'messages',
      folder,
      accountId,
      page,
      pageSize,
      demoVersion ?? 0,
    ] as const
  }
  return messagesQueryKey(folder, accountId, page, pageSize)
}

export function mailMessagesQueryRoot(isDemo: boolean) {
  return isDemo ? DEMO_MAIL_MESSAGES_QUERY_ROOT : MAIL_MESSAGES_QUERY_ROOT
}

export async function fetchMessagesPage(
  folder: string,
  accountId: string | undefined,
  page: number,
  pageSize: number
): Promise<PaginatedResponse<ApiMessageSummary>> {
  const safePageSize = normalizeListPageSize(pageSize)
  const res = await apiClient.get<ApiMessagesPayload>('/mail/messages', {
    folder,
    account_id: accountId,
    page: String(page),
    page_size: String(safePageSize),
  })
  return unwrapMessages(res)
}

export async function fetchMessagesListPage(
  folder: string,
  accountId: string | undefined,
  page: number,
  pageSize: number,
  isDemo: boolean
): Promise<PaginatedResponse<ApiMessageSummary>> {
  const safePageSize = normalizeListPageSize(pageSize)
  if (isDemo) {
    return demoListMessagesPage(folder, page, safePageSize)
  }
  return fetchMessagesPage(folder, accountId, page, safePageSize)
}

function demoListMessagesPage(
  folder: string,
  page: number,
  pageSize: number
): PaginatedResponse<ApiMessageSummary> {
  return useDemoMailStore.getState().listMessages(
    folder,
    page,
    normalizeListPageSize(pageSize)
  )
}

export function useMessages(
  folder: string,
  accountId?: string,
  page?: number,
  pageSize?: number
) {
  const { ready, authenticated } = useAuthReady()
  const isDemoMail = useIsDemoMail()
  const demoVersion = useDemoMailStore((s) => s.version)
  const pageNum = page ?? 1
  const safePageSize = pageSize ?? LIST_PAGE_SIZE

  return useQuery({
    queryKey: messagesListQueryKey(
      folder,
      accountId,
      page,
      pageSize,
      isDemoMail,
      demoVersion
    ),
    queryFn: () => {
      if (isDemoMail) {
        return demoListMessagesPage(folder, pageNum, safePageSize)
      }
      return fetchMessagesPage(folder, accountId, pageNum, safePageSize)
    },
    initialData: isDemoMail
      ? () => demoListMessagesPage(folder, pageNum, safePageSize)
      : undefined,
    placeholderData: keepPreviousData,
    staleTime: 60_000,
    enabled: ready && authenticated,
  })
}

export function useMessage(messageId: string | null) {
  const { ready, authenticated } = useAuthReady()
  const isDemoMail = useIsDemoMail()
  const demoVersion = useDemoMailStore((s) => s.version)

  return useQuery({
    queryKey: isDemoMail
      ? ['demo', 'message', messageId, demoVersion]
      : ['message', messageId],
    queryFn: () => {
      if (isDemoMail) {
        const message = useDemoMailStore.getState().getMessage(messageId!)
        if (!message) throw new Error('Message introuvable')
        return message
      }
      return apiClient.get<ApiMessageFull>(`/mail/messages/${messageId}`)
    },
    initialData:
      isDemoMail && messageId
        ? () => {
            const message = useDemoMailStore.getState().getMessage(messageId)
            if (!message) throw new Error('Message introuvable')
            return message
          }
        : undefined,
    enabled: ready && authenticated && !!messageId,
    placeholderData: keepPreviousData,
    staleTime: 5 * 60_000,
  })
}

/** Backend returns `{ thread_id, messages }`; normalize to array for consumers. */
export function unwrapThreadMessages(
  res:
    | ApiMessageFull[]
    | { messages?: ApiMessageFull[]; thread_id?: string }
    | null
    | undefined
): ApiMessageFull[] {
  if (!res) return []
  if (Array.isArray(res)) return res
  return Array.isArray(res.messages) ? res.messages : []
}

export function useThread(threadId: string | null) {
  const { ready, authenticated } = useAuthReady()
  const isDemoMail = useIsDemoMail()
  const demoVersion = useDemoMailStore((s) => s.version)

  return useQuery({
    queryKey: isDemoMail
      ? ['demo', 'thread', 'v2', threadId, demoVersion]
      : ['thread', 'v2', threadId],
    queryFn: () => {
      if (isDemoMail) {
        return useDemoMailStore.getState().getThread(threadId!)
      }
      return apiClient.get<
        ApiMessageFull[] | { messages?: ApiMessageFull[]; thread_id?: string }
      >(`/mail/threads/${threadId}`)
    },
    select: isDemoMail ? undefined : unwrapThreadMessages,
    enabled: ready && authenticated && !!threadId,
  })
}

export function useMailAccounts() {
  const { ready, authenticated } = useAuthReady()
  const isDemoMail = useIsDemoMail()

  return useQuery({
    queryKey: ['accounts', isDemoMail ? 'demo' : null],
    queryFn: async () => {
      if (isDemoMail) return [DEMO_MAIL_ACCOUNT]
      const res = await apiClient.get<ApiMailAccount[] | { accounts: ApiMailAccount[] }>(
        '/mail/accounts'
      )
      return Array.isArray(res) ? res : (res.accounts ?? [])
    },
    initialData: isDemoMail ? () => [DEMO_MAIL_ACCOUNT] : undefined,
    staleTime: 5 * 60_000,
    enabled: ready && authenticated,
    retry: isDemoMail ? false : 1,
  })
}

export function useMailSearch(filter: MessageSearchFilter | null) {
  const queryClient = useQueryClient()
  const { ready, authenticated } = useAuthReady()
  const isDemoMail = useIsDemoMail()
  const demoVersion = useDemoMailStore((s) => s.version)

  return useQuery({
    queryKey: isDemoMail
      ? ['demo', 'mail-search', filter, demoVersion]
      : ['mail-search', filter],
    queryFn: async () => {
      if (isDemoMail) {
        return useDemoMailStore.getState().searchMessages(filter)
      }

      const params: Record<string, string | undefined> = {}
      if (filter) {
        if (filter.q) params.q = filter.q
        if (filter.from) params.sender = filter.from
        if (filter.label) params.label = filter.label
        if (filter.account_id) params.account_id = filter.account_id
        if (filter.date_from) params.date_from = filter.date_from
        if (filter.date_to) params.date_to = filter.date_to
        if (filter.has_attachment !== undefined) params.has_attachment = String(filter.has_attachment)
      }

      try {
        const res = await apiClient.get<ApiMessagesPayload>('/mail/search', params)
        return unwrapMessages(res)
      } catch (err) {
        if (err instanceof OfflineError) {
          const cached = queryClient.getQueriesData<PaginatedResponse<ApiMessageSummary>>({
            queryKey: ['messages'],
          })
          const allMessages: ApiMessageSummary[] = []
          for (const [, data] of cached) {
            if (data?.data) allMessages.push(...data.data)
          }

          const q = filter?.q?.toLowerCase()
          const filtered = allMessages.filter((m) => {
            if (q) {
              const matchSubject = m.subject.toLowerCase().includes(q)
              const matchSnippet = m.snippet.toLowerCase().includes(q)
              const matchFrom = m.from.some(
                (r) => r.address.toLowerCase().includes(q) || r.name.toLowerCase().includes(q)
              )
              if (!matchSubject && !matchSnippet && !matchFrom) return false
            }
            if (filter?.from) {
              const fromMatch = m.from.some(
                (r) =>
                  r.address.toLowerCase().includes(filter.from!.toLowerCase()) ||
                  r.name.toLowerCase().includes(filter.from!.toLowerCase())
              )
              if (!fromMatch) return false
            }
            if (filter?.label) {
              if (!m.labels.includes(filter.label)) return false
            }
            if (filter?.has_attachment !== undefined) {
              if (m.has_attachments !== filter.has_attachment) return false
            }
            return true
          })

          return { data: filtered, pagination: { page: 1, page_size: filtered.length } }
        }
        throw err
      }
    },
    initialData: isDemoMail
      ? () => useDemoMailStore.getState().searchMessages(filter)
      : undefined,
    enabled: ready && authenticated && isMessageSearchFilterActive(filter),
  })
}
