"use client"

import { useEffect, useMemo, useState } from "react"
import { usePaginatedQuery } from "convex/react"
import { api } from "@/convex/_generated/api"
import type { Id } from "@/convex/_generated/dataModel"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { mapTicketsFromServerList } from "@/lib/mappers/ticket"
import type { Ticket } from "@/lib/schemas/ticket"
import { useAuth } from "@/lib/auth-client"
import Link from "next/link"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@/components/ui/empty"
import { Skeleton } from "@/components/ui/skeleton"
import { Spinner } from "@/components/ui/spinner"
import { Button } from "@/components/ui/button"
import { PortalTicketCard } from "@/components/portal/portal-ticket-card"
import {
  PortalTicketFilters,
  defaultPortalTicketFilters,
  type PortalTicketFiltersState,
} from "@/components/portal/portal-ticket-filters"
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react"

/** Número de tickets por página no portal */
const TICKETS_PER_PAGE = 20

export function PortalTicketList() {
  const { convexUserId, session, machineContext, role } = useAuth()

  const viewerId = (convexUserId ?? machineContext?.assignedUserId ?? null) as Id<"users"> | null

  // Argumentos para a query paginada
  const ticketsArgs = useMemo(() => {
    if (!viewerId) return "skip" as const
    return {
      tenantId: session?.user.tenantId ?? DEFAULT_TENANT_ID,
      viewerId,
    }
  }, [viewerId, session?.user.tenantId])

  // Query paginada para evitar carregar todos os tickets de uma vez
  const {
    results: ticketsRaw,
    status: paginationStatus,
    loadMore,
  } = usePaginatedQuery(
    api.tickets.listPaginated,
    ticketsArgs,
    { initialNumItems: TICKETS_PER_PAGE }
  )

  // Indicadores de estado da paginação
  const isLoadingFirstPage = paginationStatus === "LoadingFirstPage"
  const isLoadingMore = paginationStatus === "LoadingMore"
  const canLoadMore = paginationStatus === "CanLoadMore"

  const tickets = useMemo(() => {
    if (!ticketsRaw) return []
    return mapTicketsFromServerList((ticketsRaw as unknown[]) ?? [])
  }, [ticketsRaw])

  const [initialLoadCompleted, setInitialLoadCompleted] = useState(false)

  useEffect(() => {
    if (initialLoadCompleted) return
    if (!viewerId) return
    if (isLoadingFirstPage) return
    setInitialLoadCompleted(true)
  }, [initialLoadCompleted, viewerId, isLoadingFirstPage])

  const [filters, setFilters] = useState<PortalTicketFiltersState>(defaultPortalTicketFilters)

  // No app desktop, colaboradores e gestores não devem ver filtros avançados
  const hideAdvancedFilters = Boolean(machineContext) && (role === "collaborator" || role === "manager")

  const queueOptions = useMemo(() => {
    const set = new Set<string>()
    ;(tickets as Ticket[]).forEach((ticket) => {
      if (ticket.queue) {
        set.add(ticket.queue)
      }
    })
    return Array.from(set).sort((a, b) => a.localeCompare(b, "pt-BR"))
  }, [tickets])

  const companyOptions = useMemo(() => {
    const set = new Set<string>()
    ;(tickets as Ticket[]).forEach((ticket) => {
      const name = ticket.company?.name
      if (name) set.add(name)
    })
    return Array.from(set).sort((a, b) => a.localeCompare(b, "pt-BR"))
  }, [tickets])

  const categoryOptions = useMemo(() => {
    const map = new Map<string, string>()
    ;(tickets as Ticket[]).forEach((ticket) => {
      if (ticket.category?.id && ticket.category.name) {
        map.set(ticket.category.id, ticket.category.name)
      }
    })
    return Array.from(map.entries())
      .map(([id, name]) => ({ id, name }))
      .sort((a, b) => a.name.localeCompare(b.name, "pt-BR"))
  }, [tickets])

  const assigneeOptions = useMemo(() => {
    const map = new Map<string, string>()
    ;(tickets as Ticket[]).forEach((ticket) => {
      if (ticket.assignee?.id && ticket.assignee.name) {
        map.set(ticket.assignee.id, ticket.assignee.name)
      }
    })
    return Array.from(map.entries())
      .map(([id, name]) => ({ id, name }))
      .sort((a, b) => a.name.localeCompare(b.name, "pt-BR"))
  }, [tickets])

  const lastResolvedNoCsat = useMemo(() => {
    const resolved = (tickets as Ticket[])
      .filter((t) => t.status === "RESOLVED" && (t.csatScore == null))
      .sort((a, b) => (b.resolvedAt?.getTime?.() ?? 0) - (a.resolvedAt?.getTime?.() ?? 0))
    return resolved[0] ?? null
  }, [tickets])

  const parseDateInput = (value: string | null, options?: { endOfDay?: boolean }) => {
    if (!value) return null
    const [year, month, day] = value.split("-").map((part) => Number(part))
    if (!year || !month || !day) return null
    const date = new Date(
      year,
      month - 1,
      day,
      options?.endOfDay ? 23 : 0,
      options?.endOfDay ? 59 : 0,
      options?.endOfDay ? 59 : 0,
      options?.endOfDay ? 999 : 0
    )
    if (Number.isNaN(date.getTime())) return null
    return date
  }

  const filteredTickets = useMemo(() => {
    const fromDate = parseDateInput(filters.dateFrom)
    const toDate = parseDateInput(filters.dateTo, { endOfDay: true })
    return (tickets as Ticket[])
      .filter((ticket) => {
        if (filters.queue && ticket.queue !== filters.queue) return false
        if (filters.company && ticket.company?.name !== filters.company) return false
        if (filters.categoryId && ticket.category?.id !== filters.categoryId) return false
        if (filters.assigneeId && ticket.assignee?.id !== filters.assigneeId) return false
        const isResolved = ticket.status === "RESOLVED"
        if (filters.status === "active" && isResolved) return false
        if (filters.status === "resolved" && !isResolved) return false
        const createdAt = ticket.createdAt instanceof Date ? ticket.createdAt : new Date(ticket.createdAt)
        if (fromDate && createdAt < fromDate) return false
        if (toDate && createdAt > toDate) return false
        return true
      })
      .sort((a, b) => {
        const aDate = a.createdAt instanceof Date ? a.createdAt.getTime() : new Date(a.createdAt).getTime()
        const bDate = b.createdAt instanceof Date ? b.createdAt.getTime() : new Date(b.createdAt).getTime()
        return filters.sort === "oldest" ? aDate - bDate : bDate - aDate
      })
  }, [filters, tickets])

  const handleFiltersChange = (partial: Partial<PortalTicketFiltersState>) => {
    setFilters((prev) => ({ ...prev, ...partial }))
  }

  const handleResetFilters = () => {
    setFilters(defaultPortalTicketFilters)
    setCurrentPage(1)
  }

  // Estado de paginação no cliente
  const [currentPage, setCurrentPage] = useState(1)
  const itemsPerPage = TICKETS_PER_PAGE
  const totalFilteredTickets = filteredTickets.length
  const totalPages = Math.max(1, Math.ceil(totalFilteredTickets / itemsPerPage))

  // Tickets da página atual
  const paginatedTickets = useMemo(() => {
    const startIndex = (currentPage - 1) * itemsPerPage
    const endIndex = startIndex + itemsPerPage
    return filteredTickets.slice(startIndex, endIndex)
  }, [filteredTickets, currentPage, itemsPerPage])

  // Reseta para a primeira página quando os filtros mudam
  useEffect(() => {
    setCurrentPage(1)
  }, [filters])

  const isLoading = !initialLoadCompleted

  if (isLoading) {
    return (
      <div className="space-y-4">
        <div className="flex items-center justify-between">
          <div>
            <h2 className="text-lg font-semibold text-neutral-900">Meus chamados</h2>
            <p className="text-sm text-neutral-600">Acompanhe seus tickets e veja as últimas atualizações.</p>
          </div>
        </div>
        <Card className="rounded-2xl border border-slate-200 bg-white p-5 shadow-sm">
          <div className="grid grid-cols-3 gap-4">
            <Skeleton className="h-10 rounded-lg" />
            <Skeleton className="h-10 rounded-lg" />
            <Skeleton className="h-10 rounded-lg" />
          </div>
        </Card>
        <div className="grid gap-4">
          {Array.from({ length: 4 }).map((_, index) => (
            <PortalTicketCardSkeleton key={index} />
          ))}
        </div>
      </div>
    )
  }

  if (!viewerId || !tickets.length) {
    return (
      <Card className="rounded-2xl border border-slate-200 bg-white shadow-sm">
        <CardHeader className="px-5 py-5">
          <CardTitle className="text-lg font-semibold text-neutral-900">Meus chamados</CardTitle>
        </CardHeader>
        <CardContent className="px-5 pb-6">
          <Empty>
            <EmptyHeader>
              <EmptyMedia variant="icon">
                <span className="inline-block size-3 rounded-full border border-slate-300 bg-[#00e8ff]" />
              </EmptyMedia>
              <EmptyTitle className="text-neutral-900">Nenhum ticket encontrado</EmptyTitle>
              <EmptyDescription className="text-neutral-600">
                Ajuste os filtros ou crie um novo ticket.
              </EmptyDescription>
            </EmptyHeader>
            <div className="mt-4">
              <Button asChild className="rounded-full bg-neutral-900 px-4 text-sm font-semibold text-white hover:bg-neutral-900/90">
                <Link href="/portal/tickets/new">Novo ticket</Link>
              </Button>
            </div>
          </Empty>
        </CardContent>
      </Card>
    )
  }

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between">
        <div>
          <h2 className="text-lg font-semibold text-neutral-900">Meus chamados</h2>
          <p className="text-sm text-neutral-600">Acompanhe seus tickets e veja as últimas atualizações.</p>
        </div>
      </div>
      {lastResolvedNoCsat ? (
        <div className="rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
          Como foi seu último atendimento? Avalie o chamado #{lastResolvedNoCsat.reference}.{' '}
          <Link href={`/portal/tickets/${lastResolvedNoCsat.id}#csat`} className="font-semibold underline">
            Avaliar agora
          </Link>
        </div>
      ) : null}
      <PortalTicketFilters
        filters={filters}
        onFiltersChange={handleFiltersChange}
        onReset={handleResetFilters}
        queues={queueOptions}
        companies={companyOptions}
        categories={categoryOptions}
        assignees={assigneeOptions}
        hideAdvancedFilters={hideAdvancedFilters}
      />
      {filteredTickets.length === 0 ? (
        <Card className="rounded-2xl border border-slate-200 bg-white py-8 text-center shadow-sm">
          <CardContent className="space-y-3">
            <CardTitle className="text-lg font-semibold text-neutral-900">Nenhum ticket corresponde aos filtros</CardTitle>
            <p className="text-sm text-neutral-600">
              Ajuste as opções acima ou limpe os filtros para visualizar novamente.
            </p>
            <Button variant="outline" onClick={handleResetFilters} className="mt-2 rounded-full">
              Limpar filtros
            </Button>
          </CardContent>
        </Card>
      ) : (
        <>
          <div className="grid gap-4">
            {paginatedTickets.map((ticket) => (
              <PortalTicketCard key={ticket.id} ticket={ticket} />
            ))}
          </div>

          {/* Controles de paginação numerada */}
          {totalFilteredTickets > itemsPerPage && (
            <div className="flex flex-col items-center gap-4 rounded-2xl border border-slate-200 bg-white px-4 py-3 shadow-sm sm:flex-row sm:justify-between">
              <div className="text-sm text-neutral-600">
                Mostrando {((currentPage - 1) * itemsPerPage) + 1} a {Math.min(currentPage * itemsPerPage, totalFilteredTickets)} de {totalFilteredTickets} tickets
                {canLoadMore && (
                  <span className="ml-1 text-neutral-400">(mais disponíveis)</span>
                )}
              </div>

              <div className="flex items-center gap-1">
                {/* Primeira página */}
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => setCurrentPage(1)}
                  disabled={currentPage === 1}
                  className="h-8 w-8 rounded-full p-0"
                  title="Primeira página"
                >
                  <ChevronsLeft className="h-4 w-4" />
                </Button>

                {/* Página anterior */}
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
                  disabled={currentPage === 1}
                  className="h-8 w-8 rounded-full p-0"
                  title="Página anterior"
                >
                  <ChevronLeft className="h-4 w-4" />
                </Button>

                {/* Números das páginas */}
                <div className="flex items-center gap-1 px-2">
                  {generatePageNumbers(currentPage, totalPages).map((pageNum, idx) =>
                    pageNum === "..." ? (
                      <span key={`ellipsis-${idx}`} className="px-2 text-neutral-400">
                        ...
                      </span>
                    ) : (
                      <Button
                        key={pageNum}
                        variant={currentPage === pageNum ? "default" : "outline"}
                        size="sm"
                        onClick={() => setCurrentPage(pageNum as number)}
                        className="h-8 min-w-[32px] rounded-full px-2"
                      >
                        {pageNum}
                      </Button>
                    )
                  )}
                </div>

                {/* Próxima página */}
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
                  disabled={currentPage === totalPages}
                  className="h-8 w-8 rounded-full p-0"
                  title="Próxima página"
                >
                  <ChevronRight className="h-4 w-4" />
                </Button>

                {/* Última página */}
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => setCurrentPage(totalPages)}
                  disabled={currentPage === totalPages}
                  className="h-8 w-8 rounded-full p-0"
                  title="Última página"
                >
                  <ChevronsRight className="h-4 w-4" />
                </Button>
              </div>

              {/* Botão para carregar mais do servidor */}
              {canLoadMore && currentPage === totalPages && (
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => loadMore(TICKETS_PER_PAGE)}
                  disabled={isLoadingMore}
                  className="flex items-center gap-2 rounded-full"
                >
                  {isLoadingMore ? (
                    <>
                      <Spinner className="size-4" />
                      Carregando...
                    </>
                  ) : (
                    "Carregar mais tickets"
                  )}
                </Button>
              )}
            </div>
          )}
        </>
      )}
    </div>
  )
}

/** Skeleton do card de ticket para estado de carregamento */
function PortalTicketCardSkeleton() {
  return (
    <Card className="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm">
      <CardHeader className="flex flex-row items-start justify-between gap-3 px-5 pb-3 pt-5">
        <div className="flex-1">
          <div className="flex items-center gap-2">
            <Skeleton className="h-4 w-16" />
            <Skeleton className="h-4 w-24" />
          </div>
          <Skeleton className="mt-2 h-6 w-3/4" />
        </div>
        <div className="flex flex-col items-end gap-2">
          <Skeleton className="h-9 w-24 rounded-full" />
          <Skeleton className="h-6 w-16 rounded-full" />
        </div>
      </CardHeader>
      <CardContent className="flex flex-wrap items-center justify-between gap-4 border-t border-slate-100 px-5 py-4">
        <div className="flex flex-col gap-1">
          <Skeleton className="h-3 w-8" />
          <Skeleton className="h-4 w-20" />
        </div>
        <div className="flex flex-col gap-1">
          <Skeleton className="h-3 w-12" />
          <Skeleton className="h-4 w-24" />
        </div>
        <div className="flex flex-col gap-1">
          <Skeleton className="h-3 w-20" />
          <Skeleton className="h-4 w-28" />
        </div>
        <div className="flex flex-col gap-1">
          <Skeleton className="h-3 w-16" />
          <Skeleton className="h-4 w-32" />
        </div>
      </CardContent>
    </Card>
  )
}

/**
 * Gera array de números de página para exibição.
 * Mostra primeira, última e páginas próximas à atual com reticências.
 */
function generatePageNumbers(currentPage: number, totalPages: number): (number | "...")[] {
  if (totalPages <= 7) {
    return Array.from({ length: totalPages }, (_, i) => i + 1)
  }

  const pages: (number | "...")[] = []

  // Sempre mostra a primeira página
  pages.push(1)

  if (currentPage > 3) {
    pages.push("...")
  }

  // Páginas próximas à atual
  const start = Math.max(2, currentPage - 1)
  const end = Math.min(totalPages - 1, currentPage + 1)

  for (let i = start; i <= end; i++) {
    if (!pages.includes(i)) {
      pages.push(i)
    }
  }

  if (currentPage < totalPages - 2) {
    pages.push("...")
  }

  // Sempre mostra a última página
  if (!pages.includes(totalPages)) {
    pages.push(totalPages)
  }

  return pages
}
