import { defineStore } from 'pinia'
import type {
    MailFolderDto,
    MailMessageHeaderDto,
    MailMessageDetailDto,
} from '~/modules/mail/services/dto/mail'
import { useMailService } from '~/modules/mail/services/mail'

const POLL_INTERVAL_MS = 30 * 1000 // 30 secondes

export const useMailStore = defineStore('mail', () => {
    // ─── State ────────────────────────────────────────────────────────────────

    /** Liste plate des dossiers (reçue de l'API) */
    const folders = ref<MailFolderDto[]>([])

    /** Chemin du dossier actuellement sélectionné */
    const selectedFolderPath = ref<string | null>(null)

    /** Messages du dossier sélectionné (accumulés pour infinite scroll) */
    const messages = ref<MailMessageHeaderDto[]>([])

    /** Cursor de pagination pour la page suivante (null = plus de données) */
    const messagesCursor = ref<string | null>(null)

    /** Chargement en cours (messages) */
    const messagesLoading = ref(false)

    /** ID du message sélectionné pour lecture */
    const selectedMessageId = ref<number | null>(null)

    /** Détail complet du message sélectionné (body + PJ) */
    const selectedMessageDetail = ref<MailMessageDetailDto | null>(null)

    /** Chargement du détail en cours */
    const detailLoading = ref(false)

    /** Sync IMAP en cours (déclenchée manuellement) */
    const syncing = ref(false)

    /** Nombre total de messages non lus (toutes boîtes confondues) */
    const globalUnreadCount = ref(0)

    /** Erreur courante (null si aucune) */
    const error = ref<string | null>(null)

    let pollTimer: ReturnType<typeof setInterval> | null = null

    // ─── Getters ──────────────────────────────────────────────────────────────

    /**
     * Nombre de non-lus dans INBOX uniquement (utilisé dans la sidebar).
     */
    const inboxUnread = computed(() => {
        const inbox = folders.value.find(
            (f) => f.path === 'INBOX' || f.path.toUpperCase() === 'INBOX',
        )
        return inbox?.unreadCount ?? 0
    })

    /**
     * Construit l'arbre de dossiers depuis la liste plate.
     * Les dossiers sans parentPath sont à la racine.
     * Les enfants sont triés alphabétiquement par displayName.
     */
    const folderTree = computed((): MailFolderDto[] => {
        const map = new Map<string, MailFolderDto>()
        const roots: MailFolderDto[] = []

        // Initialiser chaque dossier avec children vide
        folders.value.forEach((folder) => {
            map.set(folder.path, { ...folder, children: [] })
        })

        // Construire l'arbre
        map.forEach((folder) => {
            if (folder.parentPath && map.has(folder.parentPath)) {
                const parent = map.get(folder.parentPath)!
                parent.children = parent.children ?? []
                parent.children.push(folder)
            } else {
                roots.push(folder)
            }
        })

        // Trier les enfants alphabétiquement
        function sortChildren(nodes: MailFolderDto[]): MailFolderDto[] {
            return nodes
                .map((n) => ({
                    ...n,
                    children: n.children ? sortChildren(n.children) : undefined,
                }))
                .sort((a, b) => a.displayName.localeCompare(b.displayName, 'fr'))
        }

        return sortChildren(roots)
    })

    /**
     * Indique si le cursor de pagination est disponible (plus de messages à charger).
     */
    const hasMoreMessages = computed(() => messagesCursor.value !== null)

    // ─── Actions ──────────────────────────────────────────────────────────────

    /**
     * Charge la liste des dossiers depuis l'API et met à jour globalUnreadCount.
     */
    async function fetchFolders(): Promise<void> {
        const service = useMailService()
        try {
            folders.value = await service.listFolders()
            globalUnreadCount.value = folders.value.reduce(
                (sum, f) => sum + f.unreadCount,
                0,
            )
        } catch {
            // Silently ignore polling errors (ne pas interrompre l'UX)
        }
    }

    /**
     * Charge les messages du dossier sélectionné.
     * @param append - Si true, ajoute à la liste existante (infinite scroll). Si false, remplace.
     */
    async function fetchMessages(append = false): Promise<void> {
        if (!selectedFolderPath.value) return
        if (messagesLoading.value) return

        messagesLoading.value = true
        error.value = null

        const service = useMailService()
        try {
            const cursor = append ? (messagesCursor.value ?? undefined) : undefined
            const page = await service.listMessages(selectedFolderPath.value, cursor)

            if (append) {
                messages.value = [...messages.value, ...page.items]
            } else {
                messages.value = page.items
            }
            messagesCursor.value = page.nextCursor
        } catch (err) {
            error.value = err instanceof Error ? err.message : 'Erreur lors du chargement des messages.'
        } finally {
            messagesLoading.value = false
        }
    }

    /**
     * Sélectionne un dossier et charge ses messages (reset de la pagination).
     * @param path - Chemin du dossier (ex: "INBOX")
     */
    async function selectFolder(path: string): Promise<void> {
        if (selectedFolderPath.value === path) return
        selectedFolderPath.value = path
        messages.value = []
        messagesCursor.value = null
        selectedMessageId.value = null
        selectedMessageDetail.value = null
        await fetchMessages()
    }

    /**
     * Marque un message comme lu ou non-lu.
     * Met à jour le state local (messages + detail) sans refetch.
     */
    async function markRead(id: number, read: boolean): Promise<void> {
        const service = useMailService()
        const updated = await service.markRead(id, read)

        // Mise à jour optimiste dans la liste
        const idx = messages.value.findIndex((m) => m.id === id)
        if (idx !== -1) {
            messages.value[idx] = { ...messages.value[idx], isRead: updated.isRead }
        }

        // Mise à jour dans le détail si ouvert
        if (selectedMessageDetail.value?.header.id === id) {
            selectedMessageDetail.value = {
                ...selectedMessageDetail.value,
                header: { ...selectedMessageDetail.value.header, isRead: updated.isRead },
            }
        }

        // Mettre à jour le compteur du dossier
        await _refreshFolderUnreadCount()
    }

    /**
     * Sélectionne un message et charge son détail complet (body + PJ).
     * Marque automatiquement le message comme lu si ce n'est pas déjà le cas.
     * @param id - ID BDD du message
     */
    async function selectMessage(id: number): Promise<void> {
        if (selectedMessageId.value === id) return
        selectedMessageId.value = id
        selectedMessageDetail.value = null
        detailLoading.value = true

        const service = useMailService()
        try {
            const detail = await service.getMessage(id)
            selectedMessageDetail.value = detail

            // Auto-mark as read si nécessaire
            if (!detail.header.isRead) {
                await markRead(id, true)
            }
        } finally {
            detailLoading.value = false
        }
    }

    /**
     * Marque un message comme étoilé ou non-étoilé.
     * Met à jour le state local sans refetch.
     */
    async function markFlagged(id: number, flagged: boolean): Promise<void> {
        const service = useMailService()
        const updated = await service.markFlagged(id, flagged)

        const idx = messages.value.findIndex((m) => m.id === id)
        if (idx !== -1) {
            messages.value[idx] = { ...messages.value[idx], isFlagged: updated.isFlagged }
        }

        if (selectedMessageDetail.value?.header.id === id) {
            selectedMessageDetail.value = {
                ...selectedMessageDetail.value,
                header: { ...selectedMessageDetail.value.header, isFlagged: updated.isFlagged },
            }
        }
    }

    /**
     * Déclenche une synchronisation IMAP asynchrone.
     * Recharge les dossiers après 2s pour refléter les nouveaux messages.
     */
    async function triggerSync(): Promise<void> {
        if (syncing.value) return
        syncing.value = true
        const service = useMailService()
        try {
            await service.triggerSync()
            // Laisser le temps au handler Messenger de traiter
            setTimeout(async () => {
                await fetchFolders()
                if (selectedFolderPath.value) {
                    await fetchMessages(false)
                }
                syncing.value = false
            }, 2000)
        } catch {
            syncing.value = false
        }
    }

    /**
     * Arrête le polling. À appeler au logout.
     */
    function stopPolling(): void {
        if (pollTimer) {
            clearInterval(pollTimer)
            pollTimer = null
        }
    }

    /**
     * Démarre le polling toutes les 30s pour mettre à jour globalUnreadCount.
     * À appeler dans app.vue ou le layout default au login.
     * Idempotent : un seul timer actif à la fois.
     */
    function startPolling(): void {
        if (pollTimer) return
        fetchFolders() // Charge immédiatement
        pollTimer = setInterval(fetchFolders, POLL_INTERVAL_MS)

        // Cleanup automatique si le scope du store est détruit
        if (getCurrentScope()) {
            onScopeDispose(stopPolling)
        }
    }

    /**
     * Rafraîchit les compteurs non-lus du dossier actuel depuis l'API.
     * Usage interne — appelé après markRead.
     */
    async function _refreshFolderUnreadCount(): Promise<void> {
        const service = useMailService()
        try {
            const updatedFolders = await service.listFolders()
            folders.value = updatedFolders
            globalUnreadCount.value = updatedFolders.reduce(
                (sum, f) => sum + f.unreadCount,
                0,
            )
        } catch {
            // Silently ignore
        }
    }

    return {
        // State (readonly pour les consommateurs)
        folders: readonly(folders),
        selectedFolderPath: readonly(selectedFolderPath),
        messages: readonly(messages),
        messagesCursor: readonly(messagesCursor),
        messagesLoading: readonly(messagesLoading),
        selectedMessageId: readonly(selectedMessageId),
        selectedMessageDetail: readonly(selectedMessageDetail),
        detailLoading: readonly(detailLoading),
        syncing: readonly(syncing),
        globalUnreadCount: readonly(globalUnreadCount),
        error: readonly(error),
        // Getters
        inboxUnread,
        folderTree,
        hasMoreMessages,
        // Actions
        fetchFolders,
        selectFolder,
        fetchMessages,
        selectMessage,
        markRead,
        markFlagged,
        triggerSync,
        startPolling,
        stopPolling,
    }
})
