"use client"

import { useState } from "react"
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
import { toast } from "sonner"
import { confirm } from "@/shared/components/confirm-dialog"
import type { DataViewChangeEvent, DataViewPaginationState, DataViewSorting } from "@/shared/data-view/table-view"

// ── Types ──

export type CrudDialogClient = {
    list(query?: any): Promise<any>
    create(payload: any): Promise<any>
    update(id: string, payload: any): Promise<any>
    destroy(id: string): Promise<any>
}

export type UseCrudDialogOptions<TClient extends CrudDialogClient> = {
    queryKey: string[]
    getClient: () => TClient
    resourceLabel?: string
}

type CrudListShape = {
    data?: unknown
    meta?: {
        last_page?: number
        total?: number
    }
    pagination?: {
        last_page?: number
        total?: number
    }
}

function normalizeCrudListResponse(response: unknown): {
    items: any[]
    meta?: { last_page?: number; total?: number }
} {
    const root = (response ?? {}) as CrudListShape
    const directData = root.data

    if (Array.isArray(directData)) {
        return { items: directData, meta: root.meta ?? root.pagination }
    }

    if (directData && typeof directData === "object") {
        const nested = directData as CrudListShape
        if (Array.isArray(nested.data)) {
            return {
                items: nested.data,
                meta: nested.meta ?? nested.pagination ?? root.meta ?? root.pagination,
            }
        }
    }

    return { items: [], meta: root.meta ?? root.pagination }
}

// ── Hook ──

export function useCrudDialog<TClient extends CrudDialogClient>({
    queryKey,
    getClient,
    resourceLabel = "item",
}: UseCrudDialogOptions<TClient>) {
    const client = getClient()
    const queryClient = useQueryClient()

    // ── Local pagination state (no URL pollution) ──
    const [page, setPage] = useState(1)
    const [pageSize, setPageSize] = useState(10)
    const [sortBy, setSortBy] = useState<string | null>(null)
    const [sortOrder, setSortOrder] = useState<"asc" | "desc" | null>(null)

    // ── Form dialog state ──
    const [isFormOpen, setIsFormOpen] = useState(false)
    const [editingId, setEditingId] = useState<string | null>(null)
    const [editingItem, setEditingItem] = useState<any>(null)

    const fullQueryKey = [...queryKey, { page, pageSize, sortBy, sortOrder }]

    const { data, isLoading } = useQuery({
        queryKey: fullQueryKey,
        queryFn: async () => {
            const params: Record<string, unknown> = { page, per_page: pageSize }
            if (sortBy) params.sort_by = sortBy
            if (sortOrder) params.sort_order = sortOrder

            try {
                return await client.list(params)
            } catch {
                // Some endpoints ignore/reject pagination params; retry without params.
                return client.list()
            }
        },
    })

    const normalized = normalizeCrudListResponse(data)
    const items = normalized.items
    const meta = normalized.meta

    const pagination: DataViewPaginationState = {
        page,
        pageSize,
        pageCount: meta?.last_page ?? 1,
        total: meta?.total ?? 0,
    }

    const sorting: DataViewSorting = sortBy
        ? [{ id: sortBy, desc: sortOrder === "desc" }]
        : []

    const handleChange = (event: DataViewChangeEvent) => {
        switch (event.type) {
            case "pagination":
                setPage(event.pagination.page)
                setPageSize(event.pagination.pageSize)
                break
            case "sorting": {
                const sort = event.sorting[0]
                setSortBy(sort?.id ?? null)
                setSortOrder(sort ? (sort.desc ? "desc" : "asc") : null)
                setPage(1)
                break
            }
        }
    }

    const invalidateQuery = () => {
        queryClient.invalidateQueries({ queryKey })
    }

    const { mutateAsync: deleteItem } = useMutation({
        mutationFn: (id: string) => {
            const promise = client.destroy(id)
            toast.promise(promise, {
                loading: `Deleting ${resourceLabel}...`,
                success: `${resourceLabel} deleted`,
                error: `Failed to delete ${resourceLabel}`,
            })
            return promise
        },
        onSuccess: invalidateQuery,
    })

    const openCreate = () => {
        setEditingId(null)
        setEditingItem(null)
        setIsFormOpen(true)
    }

    const openEdit = (row: any) => {
        setEditingId(String(row.id))
        setEditingItem(row)
        setIsFormOpen(true)
    }

    const closeForm = () => {
        setIsFormOpen(false)
        setEditingId(null)
        setEditingItem(null)
    }

    const handleDelete = async (row: any) => {
        const confirmed = await confirm({
            title: `Delete this ${resourceLabel}?`,
            description: "This action cannot be undone.",
            confirmLabel: "Delete",
            variant: "destructive",
        })
        if (confirmed) await deleteItem(String(row.id))
    }

    const handleFormSuccess = () => {
        invalidateQuery()
        closeForm()
    }

    return {
        items,
        isLoading,
        pagination,
        sorting,
        handleChange,
        isFormOpen,
        editingId,
        editingItem,
        openCreate,
        openEdit,
        closeForm,
        handleDelete,
        handleFormSuccess,
        invalidateQuery,
    }
}
