import type {
    MailConfigurationDto,
    MailConfigurationUpdateDto,
    MailTestConnectionResultDto,
    MailFolderDto,
    MailMessageHeaderDto,
    MailMessageDetailDto,
    MailMessagesPageDto,
    MailMessageReadInput,
    MailMessageFlagInput,
    MailCreateTaskInput,
    MailLinkTaskInput,
    MailSyncResultDto,
} from '~/modules/mail/services/dto/mail'
import type { Task } from '~/modules/project-management/services/dto/task'

type BackendMailMessage = {
    id: number
    messageId: string
    uid: number
    folderPath?: string
    subject: string | null
    fromAddress: string | null
    fromName: string | null
    toAddresses: string[] | null
    ccAddresses: string[] | null
    sentAt: string | null
    isRead: boolean
    isFlagged: boolean
    hasAttachments: boolean
    snippet?: string | null
    linkedTaskIds?: number[]
}

function toAddressList(values: string[] | null | undefined): { email: string; name: string | null }[] {
    return (values ?? []).map((email) => ({ email, name: null }))
}

function mapHeader(m: BackendMailMessage, fallbackFolderPath = ''): MailMessageHeaderDto {
    return {
        id: m.id,
        messageId: m.messageId,
        folderPath: m.folderPath ?? fallbackFolderPath,
        subject: m.subject,
        fromName: m.fromName,
        fromEmail: m.fromAddress,
        toRecipients: toAddressList(m.toAddresses),
        ccRecipients: toAddressList(m.ccAddresses),
        sentAt: m.sentAt,
        receivedAt: m.sentAt ?? '',
        isRead: m.isRead,
        isFlagged: m.isFlagged,
        hasAttachments: m.hasAttachments,
        linkedTaskIds: m.linkedTaskIds ?? [],
    }
}

export function useMailService() {
    const api = useApi()

    // ─── Configuration (Admin) ────────────────────────────────────────────────

    /**
     * Récupère la configuration mail singleton.
     * Requiert ROLE_ADMIN — 403 sinon.
     */
    async function getConfiguration(): Promise<MailConfigurationDto> {
        return api.get<MailConfigurationDto>('/mail/configuration')
    }

    /**
     * Met à jour la configuration mail (PATCH merge).
     * Si payload.password est fourni, il sera chiffré côté backend.
     * Jamais retourné en clair dans la réponse.
     */
    async function updateConfiguration(
        payload: MailConfigurationUpdateDto,
    ): Promise<MailConfigurationDto> {
        return api.patch<MailConfigurationDto>(
            '/mail/configuration',
            payload as Record<string, unknown>,
            { toastSuccessKey: 'mail.configuration.saved' },
        )
    }

    /**
     * Teste la connexion IMAP avec la configuration actuelle.
     * Requiert ROLE_ADMIN.
     */
    async function testConfiguration(): Promise<MailTestConnectionResultDto> {
        return api.post<MailTestConnectionResultDto>('/mail/configuration/test', {})
    }

    // ─── Dossiers ─────────────────────────────────────────────────────────────

    /**
     * Liste tous les dossiers mail depuis la base (cache BDD, pas live IMAP).
     * Retourne une liste plate — la construction de l'arbre est faite dans le store
     * via le getter `folderTree`.
     */
    async function listFolders(): Promise<MailFolderDto[]> {
        return api.get<MailFolderDto[]>('/mail/folders')
    }

    // ─── Messages ─────────────────────────────────────────────────────────────

    /**
     * Liste les messages d'un dossier, paginés par cursor.
     * @param folderPath - Chemin du dossier (ex: "INBOX", "INBOX.Sent")
     * @param cursor - Opaque cursor retourné par la page précédente (undefined = première page)
     * @param limit - Nombre de messages par page (défaut backend : 50)
     */
    async function listMessages(
        folderPath: string,
        cursor?: string,
        limit?: number,
    ): Promise<MailMessagesPageDto> {
        const query: Record<string, unknown> = {}
        if (cursor) query.cursor = cursor
        if (limit) query.limit = limit
        const path = `/mail/folders/${encodeURIComponent(folderPath)}/messages`
        const response = await api.get<{ messages: BackendMailMessage[]; nextCursor: string | null }>(
            path,
            query,
        )
        return {
            items: response.messages.map((m) => mapHeader(m, folderPath)),
            nextCursor: response.nextCursor,
            total: response.messages.length,
        }
    }

    /**
     * Récupère le détail complet d'un message (body live IMAP, cached 5 min).
     * @param id - ID BDD du message (MailMessage.id)
     */
    async function getMessage(id: number): Promise<MailMessageDetailDto> {
        const response = await api.get<
            BackendMailMessage & {
                bodyHtml: string | null
                bodyText: string | null
                attachments: MailMessageDetailDto['attachments']
            }
        >(`/mail/messages/${id}`)
        return {
            header: mapHeader(response),
            bodyHtml: response.bodyHtml,
            bodyText: response.bodyText,
            attachments: response.attachments,
        }
    }

    // ─── Actions sur les messages ─────────────────────────────────────────────

    /**
     * Marque un message comme lu ou non-lu.
     */
    async function markRead(id: number, read: boolean): Promise<MailMessageHeaderDto> {
        const payload: MailMessageReadInput = { read }
        return api.post<MailMessageHeaderDto>(
            `/mail/messages/${id}/read`,
            payload as unknown as Record<string, unknown>,
        )
    }

    /**
     * Marque un message comme étoilé ou non-étoilé.
     */
    async function markFlagged(id: number, flagged: boolean): Promise<MailMessageHeaderDto> {
        const payload: MailMessageFlagInput = { flagged }
        return api.post<MailMessageHeaderDto>(
            `/mail/messages/${id}/flag`,
            payload as unknown as Record<string, unknown>,
        )
    }

    // ─── Intégration tâches ───────────────────────────────────────────────────

    /**
     * Crée une nouvelle tâche à partir d'un mail (subject → titre, body → description).
     * @param mailId - ID BDD du message
     * @param input - Paramètres de la tâche à créer
     */
    async function createTaskFromMail(
        mailId: number,
        input: MailCreateTaskInput,
    ): Promise<Task> {
        return api.post<Task>(
            `/mail/messages/${mailId}/create-task`,
            input as unknown as Record<string, unknown>,
            { toastSuccessKey: 'mail.task.created' },
        )
    }

    /**
     * Lie un mail à une tâche existante.
     * @param mailId - ID BDD du message
     * @param taskId - ID de la tâche existante
     */
    async function linkTask(mailId: number, taskId: number): Promise<void> {
        const payload: MailLinkTaskInput = { taskId }
        await api.post<void>(
            `/mail/messages/${mailId}/link-task`,
            payload as unknown as Record<string, unknown>,
            { toastSuccessKey: 'mail.task.linked' },
        )
    }

    /**
     * Supprime le lien entre un mail et une tâche.
     * @param mailId - ID BDD du message
     * @param taskId - ID de la tâche
     */
    async function unlinkTask(mailId: number, taskId: number): Promise<void> {
        await api.delete<void>(`/mail/messages/${mailId}/link-task/${taskId}`, {}, {
            toastSuccessKey: 'mail.task.unlinked',
        })
    }

    /**
     * Liste les mails liés à une tâche (pour l'onglet "Mails" du TaskDrawer — Phase 6).
     * @param taskId - ID de la tâche
     */
    async function listMailsForTask(taskId: number): Promise<MailMessageHeaderDto[]> {
        return api.get<MailMessageHeaderDto[]>(`/tasks/${taskId}/mails`)
    }

    // ─── Pièces jointes ───────────────────────────────────────────────────────

    /**
     * Télécharge une pièce jointe et retourne le Blob + headers.
     * Content-Disposition: attachment est géré côté backend (jamais inline).
     * @param downloadId - Identifiant opaque retourné dans MailAttachmentDto.downloadId
     */
    async function downloadAttachment(
        downloadId: string,
    ): Promise<{ data: Blob; headers: Headers }> {
        return api.getBlob(`/mail/attachments/${downloadId}`)
    }

    // ─── Synchronisation ─────────────────────────────────────────────────────

    /**
     * Déclenche une synchronisation IMAP asynchrone via Symfony Messenger.
     * Retourne immédiatement ({ dispatched: true }) — la sync se fait en arrière-plan.
     */
    async function triggerSync(): Promise<MailSyncResultDto> {
        return api.post<MailSyncResultDto>('/mail/sync', {}, {
            toastSuccessKey: 'mail.sync.dispatched',
        })
    }

    return {
        // Config
        getConfiguration,
        updateConfiguration,
        testConfiguration,
        // Dossiers
        listFolders,
        // Messages
        listMessages,
        getMessage,
        // Actions
        markRead,
        markFlagged,
        // Tâches
        createTaskFromMail,
        linkTask,
        unlinkTask,
        listMailsForTask,
        // Pièces jointes
        downloadAttachment,
        // Sync
        triggerSync,
    }
}
