"use client"

import { useEffect, useMemo, useState, type ReactNode } from "react"
import { useMutation, useQuery } from "convex/react"
import { toast } from "sonner"
import { format, parse } from "date-fns"
import { ptBR } from "date-fns/locale"
import { CalendarIcon, Pencil, X } from "lucide-react"

import { api } from "@/convex/_generated/api"
import type { Id } from "@/convex/_generated/dataModel"
import type { TicketWithDetails } from "@/lib/schemas/ticket"
import type { TicketFormDefinition, TicketFormFieldDefinition } from "@/lib/ticket-form-types"
import { mapTicketCustomFields, type TicketCustomFieldRecord } from "@/lib/ticket-custom-fields"
import { useAuth } from "@/lib/auth-client"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/calendar"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Field, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
import { Spinner } from "@/components/ui/spinner"
import { useLocalTimeZone } from "@/hooks/use-local-time-zone"

type TicketCustomFieldsListProps = {
  record?: TicketCustomFieldRecord | null
  emptyMessage?: string
  className?: string
  actionSlot?: ReactNode
}

const CLEAR_SELECT_VALUE = "__clear__"
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/

const DEFAULT_FORM: TicketFormDefinition = {
  key: "default",
  label: "Chamado",
  description: "",
  fields: [],
}

function toIsoDateString(value: unknown): string {
  if (!value && value !== 0) return ""
  if (typeof value === "string") {
    const trimmed = value.trim()
    if (!trimmed) return ""
    if (ISO_DATE_REGEX.test(trimmed)) {
      return trimmed
    }
    const parsed = new Date(trimmed)
    return Number.isNaN(parsed.getTime()) ? "" : parsed.toISOString().slice(0, 10)
  }
  const date =
    value instanceof Date
      ? value
      : typeof value === "number"
        ? new Date(value)
        : null
  if (!date || Number.isNaN(date.getTime())) {
    return ""
  }
  return date.toISOString().slice(0, 10)
}

function parseIsoDate(value: string): Date | null {
  if (!ISO_DATE_REGEX.test(value)) return null
  const parsed = parse(value, "yyyy-MM-dd", new Date())
  return Number.isNaN(parsed.getTime()) ? null : parsed
}

function buildInitialValues(
  fields: TicketFormFieldDefinition[],
  record?: TicketCustomFieldRecord | null
): Record<string, unknown> {
  if (!record) return {}
  const result: Record<string, unknown> = {}
  for (const field of fields) {
    const entry = record[field.key]
    if (!entry) continue
    const value = entry.value
    switch (field.type) {
      case "number":
        result[field.id] =
          typeof value === "number"
            ? String(value)
            : typeof value === "string"
              ? value
              : ""
        break
      case "date": {
        const isoValue = toIsoDateString(value)
        result[field.id] = isoValue
        break
      }
      case "boolean":
        if (value === null || value === undefined) {
          result[field.id] = field.required ? false : null
        } else {
          result[field.id] = Boolean(value)
        }
        break
      default:
        result[field.id] = value ?? ""
    }
  }
  return result
}

function isEmptyValue(value: unknown): boolean {
  if (value === undefined || value === null) return true
  if (typeof value === "string" && value.trim().length === 0) return true
  return false
}

function normalizeFieldValue(
  field: TicketFormFieldDefinition,
  raw: unknown
): { ok: true; value: unknown } | { ok: false; message: string } | { ok: true; skip: true } {
  if (field.type === "boolean") {
    if (raw === null || raw === undefined) {
      if (field.required) {
        return { ok: false, message: `Preencha o campo "${field.label}".` }
      }
      return { ok: true, skip: true }
    }
    return { ok: true, value: Boolean(raw) }
  }

  if (isEmptyValue(raw)) {
    if (field.required) {
      return { ok: false, message: `Preencha o campo "${field.label}".` }
    }
    return { ok: true, skip: true }
  }

  switch (field.type) {
    case "number": {
      const numeric = typeof raw === "number" ? raw : Number(String(raw).replace(",", "."))
      if (!Number.isFinite(numeric)) {
        return { ok: false, message: `Informe um valor numérico válido para "${field.label}".` }
      }
      return { ok: true, value: numeric }
    }
    case "date": {
      const value = String(raw)
      if (!value || Number.isNaN(Date.parse(value))) {
        return { ok: false, message: `Selecione uma data válida para "${field.label}".` }
      }
      return { ok: true, value }
    }
    case "select": {
      const value = String(raw)
      if (!value) {
        if (field.required) {
          return { ok: false, message: `Selecione uma opção para "${field.label}".` }
        }
        return { ok: true, skip: true }
      }
      return { ok: true, value }
    }
    default: {
      if (typeof raw === "string") {
        return { ok: true, value: raw.trim() }
      }
      return { ok: true, value: raw }
    }
  }
}

export function TicketCustomFieldsList({ record, emptyMessage, className, actionSlot }: TicketCustomFieldsListProps) {
  const entries = useMemo(() => mapTicketCustomFields(record), [record])
  const hasAction = Boolean(actionSlot)

  if (entries.length === 0) {
    return (
      <div className={cn("space-y-3", className)}>
        {hasAction ? (
          <div className="grid gap-3 sm:grid-cols-2">
            {actionSlot}
          </div>
        ) : null}
        <p className="text-sm text-neutral-500">
          {emptyMessage ?? "Nenhum campo adicional preenchido neste chamado."}
        </p>
      </div>
    )
  }

  return (
    <div className={cn("grid gap-3 sm:grid-cols-2", className)}>
      {hasAction ? actionSlot : null}
      {entries.map((entry) => (
        <div
          key={entry.key}
          className="rounded-2xl border border-slate-200 bg-white px-4 py-3 shadow-sm"
        >
          <p className="text-xs font-semibold uppercase tracking-wide text-neutral-500">{entry.label}</p>
          <p className="mt-1 text-sm font-semibold text-neutral-900">{entry.formattedValue}</p>
        </div>
      ))}
    </div>
  )
}

type TicketCustomFieldsSectionProps = {
  ticket: TicketWithDetails
  variant?: "card" | "inline"
  className?: string
}

export function TicketCustomFieldsSection({ ticket, variant = "card", className }: TicketCustomFieldsSectionProps) {
  const { convexUserId, role } = useAuth()
  const canEdit = Boolean(convexUserId && (role === "admin" || role === "agent"))
  const calendarTimeZone = useLocalTimeZone()

  const viewerId = convexUserId as Id<"users"> | null
  const tenantId = ticket.tenantId
  const ticketCompanyId = ticket.company?.id ?? null

  const ensureTicketFormDefaults = useMutation(api.tickets.ensureTicketFormDefaults)

  useEffect(() => {
    if (!canEdit || !viewerId) return
    let cancelled = false
    ;(async () => {
      try {
        await ensureTicketFormDefaults({
          tenantId,
          actorId: viewerId,
        })
      } catch (error) {
        if (!cancelled) {
          console.error("[ticket-custom-fields] Falha ao garantir campos padrão", error)
        }
      }
    })()
    return () => {
      cancelled = true
    }
  }, [canEdit, ensureTicketFormDefaults, tenantId, viewerId])

  const formsRemote = useQuery(
    api.tickets.listTicketForms,
    canEdit && viewerId
      ? { tenantId, viewerId, companyId: ticketCompanyId ? (ticketCompanyId as Id<"companies">) : undefined }
      : "skip"
  ) as TicketFormDefinition[] | undefined

  const availableForms = useMemo<TicketFormDefinition[]>(() => {
    if (!formsRemote || formsRemote.length === 0) {
      return [DEFAULT_FORM]
    }
    const hasDefault = formsRemote.some((form) => form.key === DEFAULT_FORM.key)
    if (hasDefault) {
      return formsRemote
    }
    return [DEFAULT_FORM, ...formsRemote]
  }, [formsRemote])

  const selectedForm = useMemo<TicketFormDefinition>(() => {
    const key = ticket.formTemplate ?? "default"
    return availableForms.find((form) => form.key === key) ?? availableForms[0] ?? DEFAULT_FORM
  }, [availableForms, ticket.formTemplate])

  const [editorOpen, setEditorOpen] = useState(false)
  const [customFieldValues, setCustomFieldValues] = useState<Record<string, unknown>>({})
  const [openCalendarField, setOpenCalendarField] = useState<string | null>(null)
  const [isSaving, setIsSaving] = useState(false)
  const [validationError, setValidationError] = useState<string | null>(null)
  const [currentFields, setCurrentFields] = useState<TicketCustomFieldRecord | null | undefined>(ticket.customFields)

  useEffect(() => {
    setCurrentFields(ticket.customFields)
  }, [ticket.customFields])

  const initialValues = useMemo(
    () => buildInitialValues(selectedForm.fields, currentFields),
    [selectedForm.fields, currentFields]
  )

  useEffect(() => {
    if (!editorOpen) return
    setCustomFieldValues(initialValues)
    setValidationError(null)
  }, [editorOpen, initialValues])

  const updateCustomFields = useMutation(api.tickets.updateCustomFields)

  const handleFieldChange = (field: TicketFormFieldDefinition, value: unknown) => {
    setCustomFieldValues((previous) => ({
      ...previous,
      [field.id]: value,
    }))
  }

  const handleClearField = (fieldId: string) => {
    setCustomFieldValues((previous) => {
      const next = { ...previous }
      delete next[fieldId]
      return next
    })
  }

  const handleSubmit = async () => {
    if (!viewerId) return
    const payload: Array<{ fieldId: Id<"ticketFields">; value: unknown }> = []

    for (const field of selectedForm.fields) {
      const raw = customFieldValues[field.id]
      const normalized = normalizeFieldValue(field, raw)
      if (!normalized.ok) {
        if ("message" in normalized) {
          setValidationError(normalized.message)
        }
        return
      }
      if ("skip" in normalized && normalized.skip) {
        continue
      }
      payload.push({
        fieldId: field.id as Id<"ticketFields">,
        value: "value" in normalized ? normalized.value : null,
      })
    }

    setIsSaving(true)
    setValidationError(null)
    try {
      const result = await updateCustomFields({
        ticketId: ticket.id as Id<"tickets">,
        actorId: viewerId,
        fields: payload,
      })
      setCurrentFields(result?.customFields ?? currentFields)
      toast.success("Campos personalizados atualizados!", { id: "ticket-custom-fields" })
      setEditorOpen(false)
    } catch (error) {
      console.error(error)
      toast.error("Não foi possível atualizar os campos personalizados.", { id: "ticket-custom-fields" })
    } finally {
      setIsSaving(false)
    }
  }

  const hasConfiguredFields = selectedForm.fields.length > 0

  const editActionSlot =
    canEdit && hasConfiguredFields ? (
      <button
        type="button"
        onClick={() => setEditorOpen(true)}
        className="flex h-full min-h-[88px] w-full flex-col items-start justify-center gap-1 rounded-2xl border-2 border-dashed border-slate-300 bg-slate-50/60 px-4 py-3 text-left text-sm font-semibold text-neutral-700 transition hover:border-slate-400 hover:bg-white"
      >
        <span className="inline-flex items-center gap-2 text-sm font-semibold text-neutral-900">
          <Pencil className="size-3.5 text-neutral-500" />
          Editar campos
        </span>
        <span className="text-xs font-medium text-neutral-500">Atualize informações personalizadas deste ticket.</span>
      </button>
    ) : null

  const dialog = (
    <Dialog open={editorOpen} onOpenChange={setEditorOpen}>
      <DialogContent className="max-w-3xl gap-4">
        <DialogHeader>
          <DialogTitle>Editar campos personalizados</DialogTitle>
          <DialogDescription>
            Atualize os campos adicionais deste chamado. Os campos obrigatórios devem ser preenchidos.
          </DialogDescription>
        </DialogHeader>
        {hasConfiguredFields ? (
          <div className="grid gap-4 rounded-2xl border border-slate-200 bg-white px-4 py-4 sm:grid-cols-2">
            <p className="text-sm font-semibold text-neutral-800 sm:col-span-2">Informações adicionais</p>
            {selectedForm.fields.map((field) => renderFieldEditor(field))}
          </div>
        ) : (
          <p className="text-sm text-neutral-500">Nenhum campo configurado ainda.</p>
        )}
        {validationError ? <p className="text-sm font-semibold text-rose-600">{validationError}</p> : null}
        <DialogFooter className="flex flex-col gap-2 sm:flex-row">
          <Button type="button" variant="outline" onClick={() => setEditorOpen(false)} disabled={isSaving}>
            Cancelar
          </Button>
          <Button onClick={handleSubmit} disabled={isSaving}>
            {isSaving ? "Salvando..." : "Salvar alterações"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )

  const listClassName = cn(variant === "inline" ? "sm:col-span-2 lg:col-span-3" : "", className)

  if (variant === "inline") {
    return (
      <>
        <TicketCustomFieldsList
          record={currentFields}
          emptyMessage="Nenhum campo adicional preenchido neste chamado."
          actionSlot={editActionSlot}
          className={listClassName}
        />
        {dialog}
      </>
    )
  }

  return (
    <section className={cn("space-y-3", className)}>
      <div className="flex flex-wrap items-center gap-2">
        <h3 className="text-sm font-semibold text-neutral-900">Informações adicionais</h3>
      </div>
      <TicketCustomFieldsList
        record={currentFields}
        emptyMessage="Nenhum campo adicional preenchido neste chamado."
        actionSlot={editActionSlot}
      />
      {dialog}
    </section>
  )

function renderFieldEditor(field: TicketFormFieldDefinition) {
  const value = customFieldValues[field.id]
  const fieldId = `ticket-custom-field-${field.id}`
  const isTextarea =
    field.type === "text" && (field.key.includes("observacao") || field.key.includes("permissao"))
  const spanClass =
    field.type === "boolean" || field.type === "date" || isTextarea ? "sm:col-span-2" : ""
  const helpText = field.description ? (
    <p className="text-xs text-neutral-500">{field.description}</p>
  ) : null

  if (field.type === "boolean") {
    const isIndeterminate = value === null || value === undefined
    return (
      <div
        key={field.id}
        className={cn(
          "flex items-start gap-3 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2",
          spanClass
        )}
      >
        <input
          id={fieldId}
          type="checkbox"
          className="mt-1 size-4 rounded border border-slate-300 text-[#00d6eb] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#00d6eb]/40"
          checked={Boolean(value)}
          ref={(element) => {
            if (!element) return
            element.indeterminate = isIndeterminate
          }}
          onChange={(event) => handleFieldChange(field, event.target.checked)}
        />
        <div className="flex flex-1 flex-col gap-1">
          <label htmlFor={fieldId} className="text-sm font-medium text-neutral-800">
            {field.label} {field.required ? <span className="text-destructive">*</span> : null}
          </label>
          {helpText}
          {!field.required ? (
            <button
              type="button"
              className="inline-flex items-center gap-1 text-xs font-medium text-neutral-500 transition hover:text-neutral-700"
              onClick={() => handleClearField(field.id)}
            >
              <X className="size-3" />
              Remover valor
            </button>
          ) : null}
        </div>
      </div>
    )
  }

  if (field.type === "select") {
    return (
      <Field key={field.id} className={cn("gap-1.5", spanClass)}>
        <FieldLabel className="flex items-center gap-1">
          {field.label} {field.required ? <span className="text-destructive">*</span> : null}
        </FieldLabel>
        <Select
          value={typeof value === "string" ? value : ""}
          onValueChange={(selected) => {
            if (selected === CLEAR_SELECT_VALUE) {
              handleClearField(field.id)
              return
            }
            handleFieldChange(field, selected)
          }}
        >
          <SelectTrigger>
            <SelectValue placeholder="Selecione" />
          </SelectTrigger>
          <SelectContent className="max-h-60 overflow-y-auto rounded-xl border border-slate-200 bg-white text-neutral-800 shadow-md">
            {!field.required ? (
              <SelectItem value={CLEAR_SELECT_VALUE} className="text-neutral-500">
                Limpar seleção
              </SelectItem>
            ) : null}
            {field.options.map((option) => (
              <SelectItem key={option.value} value={option.value}>
                {option.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
        {helpText}
      </Field>
    )
  }

  if (field.type === "number") {
    return (
      <Field key={field.id} className={cn("gap-1.5", spanClass)}>
        <FieldLabel className="flex items-center gap-1">
          {field.label} {field.required ? <span className="text-destructive">*</span> : null}
        </FieldLabel>
        <Input
          type="number"
          value={typeof value === "number" || typeof value === "string" ? String(value) : ""}
          onChange={(event) => handleFieldChange(field, event.target.value)}
          placeholder="0"
          className="rounded-lg border border-slate-300"
        />
        {helpText}
      </Field>
    )
  }

  if (field.type === "date") {
    const isoValue = toIsoDateString(value)
    const parsedDate = isoValue ? parseIsoDate(isoValue) : null
    return (
      <Field key={field.id} className={cn("flex flex-col gap-1.5", spanClass)}>
        <FieldLabel className="flex items-center gap-1">
          {field.label} {field.required ? <span className="text-destructive">*</span> : null}
        </FieldLabel>
        <Popover
          open={openCalendarField === field.id}
          onOpenChange={(open) => setOpenCalendarField(open ? field.id : null)}
        >
          <PopoverTrigger asChild>
            <Button
              type="button"
              variant="outline"
              className={cn(
                "justify-between rounded-lg border border-slate-300 text-left font-normal",
                !parsedDate && "text-muted-foreground"
              )}
            >
              {parsedDate ? (
                format(parsedDate, "dd/MM/yyyy", { locale: ptBR })
              ) : (
                <span>Selecionar data</span>
              )}
              <CalendarIcon className="ml-2 size-4 opacity-50" />
            </Button>
          </PopoverTrigger>
          <PopoverContent align="start" className="w-auto rounded-xl border border-slate-200 bg-white p-0 shadow-md">
            <Calendar
              mode="single"
              selected={parsedDate ?? undefined}
              onSelect={(date) => {
                handleFieldChange(field, date ? format(date, "yyyy-MM-dd") : "")
                setOpenCalendarField(null)
              }}
              timeZone={calendarTimeZone}
            />
          </PopoverContent>
        </Popover>
        {helpText}
      </Field>
    )
  }

  if (field.type === "text" && !isTextarea) {
    return (
      <Field key={field.id} className={cn("gap-1.5", spanClass)}>
        <FieldLabel className="flex items-center gap-1">
          {field.label} {field.required ? <span className="text-destructive">*</span> : null}
        </FieldLabel>
        <Input
          type="text"
          value={typeof value === "string" ? value : ""}
          onChange={(event) => handleFieldChange(field, event.target.value)}
          className="rounded-lg border border-slate-300"
        />
        {helpText}
      </Field>
    )
  }

  return (
    <Field key={field.id} className={cn("gap-1.5", spanClass)}>
      <FieldLabel className="flex items-center gap-1">
        {field.label} {field.required ? <span className="text-destructive">*</span> : null}
      </FieldLabel>
      <Textarea
        value={typeof value === "string" ? value : ""}
        onChange={(event) => handleFieldChange(field, event.target.value)}
        className="min-h-[88px] resize-none rounded-lg border border-slate-300"
      />
      {helpText}
    </Field>
  )
}

}
