'use client';

import { useEffect, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { AlertTriangle, CheckCircle2, Download, Loader2, XCircle } from 'lucide-react';
import { toast } from 'sonner';

import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';

interface SyncRecipient {
  role: string;
  signingOrder: number;
  id: number;
  name?: string;
  email?: string;
  mappedSettingKey: string | null;
}

interface AcroFormReport {
  envelopeItemId: string;
  fields: Array<{ name: string; type: string }>;
  matchedFieldNames: string[];
  missingFieldNames: string[];
  extraFieldNames: string[];
  error?: string;
}

interface SyncResult {
  syncedAt: string;
  templateId: number;
  title: string;
  recipients: SyncRecipient[];
  fieldCount: number;
  matchedFields: Array<{ label: string; fieldId: number }>;
  unmatchedTemplateFields: Array<{ label: string; fieldId: number }>;
  missingFromTemplate: string[];
  templateMeta?: {
    signingOrder: 'PARALLEL' | 'SEQUENTIAL' | null;
    distributionMethod: 'EMAIL' | 'NONE' | null;
    redirectUrl: string | null;
  };
  acroForm: AcroFormReport[];
}

function formatRelative(iso: string): string {
  const ms = Date.now() - new Date(iso).getTime();
  if (!Number.isFinite(ms) || ms < 0) return new Date(iso).toLocaleString();
  const sec = Math.floor(ms / 1000);
  if (sec < 60) return `${sec}s ago`;
  const min = Math.floor(sec / 60);
  if (min < 60) return `${min}m ago`;
  const hr = Math.floor(min / 60);
  if (hr < 24) return `${hr}h ago`;
  const day = Math.floor(hr / 24);
  if (day < 30) return `${day}d ago`;
  return new Date(iso).toLocaleDateString();
}

/**
 * "Sync from Documenso" admin button - calls GET /template/{id} on the
 * configured Documenso instance (via the per-port creds in admin settings),
 * pre-fills the recipient slot IDs into the matching documenso_*_recipient_id
 * settings, and caches the template's field name→ID map at
 * `documenso_eoi_field_map` for v2 prefillFields usage at send time.
 *
 * Saves the operator from typing 4 numeric IDs by hand and (in v2 mode)
 * eliminates the "renaming a field on Documenso silently breaks the EOI"
 * class of bug.
 */
export function TemplateSyncButton() {
  const queryClient = useQueryClient();
  const [templateIdInput, setTemplateIdInput] = useState('');
  const [lastResult, setLastResult] = useState<SyncResult | null>(null);

  // Seed the result panel from the cached report so the status survives
  // page reloads. A subsequent Sync click overwrites both this cache and
  // the local state.
  const cached = useQuery<{ data: SyncResult | null }>({
    queryKey: ['documenso', 'sync-template', 'report'],
    queryFn: () =>
      apiFetch<{ data: SyncResult | null }>('/api/v1/admin/documenso/sync-template/report'),
    staleTime: 60_000,
  });

  useEffect(() => {
    if (!lastResult && cached.data?.data) {
      // eslint-disable-next-line react-hooks/set-state-in-effect
      setLastResult(cached.data.data);

      setTemplateIdInput(String(cached.data.data.templateId));
    }
  }, [cached.data, lastResult]);

  const sync = useMutation({
    mutationFn: async (templateIdOrEnvelopeId: string) => {
      const r = await apiFetch<{ data: SyncResult }>(
        `/api/v1/admin/documenso/sync-template/${encodeURIComponent(templateIdOrEnvelopeId)}`,
        { method: 'POST' },
      );
      return r.data;
    },
    onSuccess: (result) => {
      setLastResult(result);
      toast.success(
        `Synced "${result.title}"  -  ${result.recipients.length} recipients, ${result.fieldCount} fields cached`,
      );
      void queryClient.invalidateQueries({ queryKey: ['settings', 'resolved'] });
      void queryClient.invalidateQueries({
        queryKey: ['documenso', 'sync-template', 'report'],
      });
    },
    onError: (err) => toastError(err, 'Template sync failed'),
  });

  const submit = () => {
    const raw = templateIdInput.trim();
    if (!raw) {
      toast.error('Enter a template ID (number) or envelope ID (envelope_…)');
      return;
    }
    // Accept either a numeric template ID or a Documenso 2.x envelope ID.
    // The server resolves envelope_xxx → numeric id via the list endpoint.
    const isNumeric = /^\d+$/.test(raw);
    const isEnvelopeId = /^envelope_[a-z0-9]+$/i.test(raw);
    if (!isNumeric && !isEnvelopeId) {
      toast.error('Enter a positive integer or a Documenso envelopeId (envelope_…)');
      return;
    }
    sync.mutate(raw);
  };

  return (
    <div className="rounded-md border bg-card p-4 space-y-4">
      <div>
        <div className="text-sm font-medium">Sync from Documenso</div>
        <p className="mt-1 text-xs text-muted-foreground">
          Paste either a numeric template ID (<code>123</code>) or the <code>envelope_…</code>{' '}
          string from your Documenso template URL (e.g. <code>envelope_nfafbkihzhoaihkb</code>). The
          CRM fetches the template via <code>GET /template/&#123;id&#125;</code> on the currently
          configured Documenso instance, writes the discovered recipient IDs into the slots above,
          and caches the field name→ID map for v2 <code>prefillFields</code> at send time.
        </p>
      </div>
      <div className="flex items-end gap-2">
        <div className="flex-1 space-y-1.5">
          <Label htmlFor="documenso-sync-template-id" className="text-xs">
            Template ID or envelope ID
          </Label>
          <Input
            id="documenso-sync-template-id"
            type="text"
            placeholder="123 or envelope_xxxxxxxx"
            value={templateIdInput}
            onChange={(e) => setTemplateIdInput(e.target.value)}
            disabled={sync.isPending}
          />
        </div>
        <Button onClick={submit} disabled={sync.isPending}>
          {sync.isPending ? (
            <>
              <Loader2 className="mr-2 size-3 animate-spin" /> Syncing…
            </>
          ) : (
            <>
              <Download className="mr-2 size-3" /> Sync
            </>
          )}
        </Button>
      </div>

      {lastResult && (
        <div className="rounded-md border border-emerald-200 bg-emerald-50/60 p-3 text-sm dark:border-emerald-900/40 dark:bg-emerald-950/30">
          <div className="flex items-center justify-between gap-2 font-medium text-emerald-700 dark:text-emerald-400">
            <div className="flex items-center gap-2">
              <CheckCircle2 className="size-4" />{' '}
              {lastResult.title || `Template #${lastResult.templateId}`}
            </div>
            <span className="text-xs font-normal text-muted-foreground">
              Last synced {formatRelative(lastResult.syncedAt)}
            </span>
          </div>
          <div className="mt-2 space-y-1 text-xs">
            <div className="font-medium text-muted-foreground">
              Recipients ({lastResult.recipients.length})
            </div>
            <ul className="space-y-0.5">
              {lastResult.recipients.map((r) => (
                <li key={r.id} className="flex flex-wrap items-center gap-x-2 gap-y-0.5">
                  <span className="font-mono text-xs">#{r.id}</span>
                  <span className="text-muted-foreground">·</span>
                  <span>
                    {r.role} (order {r.signingOrder})
                  </span>
                  {r.name && (
                    <>
                      <span className="text-muted-foreground">·</span>
                      <span>{r.name}</span>
                    </>
                  )}
                  {r.mappedSettingKey ? (
                    <span className="ml-auto rounded bg-emerald-100 px-1.5 py-0.5 text-xs font-medium text-emerald-800 dark:bg-emerald-950 dark:text-emerald-300">
                      → {r.mappedSettingKey}
                    </span>
                  ) : (
                    <span className="ml-auto rounded bg-amber-100 px-1.5 py-0.5 text-xs font-medium text-amber-800 dark:bg-amber-950 dark:text-amber-300">
                      no slot match
                    </span>
                  )}
                </li>
              ))}
            </ul>
            {lastResult.templateMeta && (
              <div className="pt-1.5 rounded-md bg-muted/60 px-2 py-1.5">
                <div className="font-medium text-muted-foreground">Template-level settings</div>
                <p className="text-xs text-muted-foreground">
                  Read from the template itself on Documenso. These values are bound to the
                  template, so every envelope generated from it inherits them -{' '}
                  <code>/template/use</code> does <strong>not</strong> accept overrides for these.
                  Change them in Documenso&apos;s template editor.
                </p>
                <ul className="mt-1 space-y-0.5 text-xs">
                  <li>
                    <span className="text-muted-foreground">Signing order:</span>{' '}
                    <span className="font-mono">
                      {lastResult.templateMeta.signingOrder ?? 'unset'}
                    </span>
                  </li>
                  <li>
                    <span className="text-muted-foreground">Distribution method:</span>{' '}
                    <span className="font-mono">
                      {lastResult.templateMeta.distributionMethod ?? 'unset'}
                    </span>
                    {lastResult.templateMeta.distributionMethod === 'EMAIL' && (
                      <span className="ml-1 rounded bg-amber-100 px-1.5 py-0.5 text-xs font-medium text-amber-900 dark:bg-amber-950 dark:text-amber-200">
                        ⚠️ Documenso will email recipients directly - the CRM&apos;s branded email
                        is in addition. Set to NONE on the template to let the CRM be the sole
                        sender.
                      </span>
                    )}
                  </li>
                  <li>
                    <span className="text-muted-foreground">Post-sign redirect:</span>{' '}
                    <span className="font-mono">
                      {lastResult.templateMeta.redirectUrl ?? '(none)'}
                    </span>
                  </li>
                </ul>
              </div>
            )}

            <div className="pt-1 font-medium text-muted-foreground">
              Fields: {lastResult.fieldCount} cached for <code>prefillFields</code>
              {lastResult.fieldCount === 0 && (
                <span className="ml-1 font-normal text-muted-foreground">
                  - that&apos;s fine if your template is a fillable PDF (AcroForm). The CRM will
                  fill it via <code>formValues</code>-by-name instead, same as on v1.{' '}
                  <code>prefillFields</code> is only needed if you placed field overlays directly in
                  the Documenso template editor.
                </span>
              )}
            </div>

            {lastResult.matchedFields.length > 0 && (
              <div className="pt-1.5">
                <div className="font-medium text-emerald-700 dark:text-emerald-400">
                  ✓ CRM will fill ({lastResult.matchedFields.length})
                </div>
                <div className="flex flex-wrap gap-1.5 pt-1">
                  {lastResult.matchedFields.map((f) => (
                    <span
                      key={f.fieldId}
                      className="rounded bg-emerald-100 px-1.5 py-0.5 font-mono text-xs text-emerald-900 dark:bg-emerald-950 dark:text-emerald-200"
                    >
                      {f.label} → #{f.fieldId}
                    </span>
                  ))}
                </div>
              </div>
            )}

            {lastResult.unmatchedTemplateFields.length > 0 && (
              <div className="pt-1.5">
                <div className="font-medium text-amber-700 dark:text-amber-400">
                  ⚠️ Template fields the CRM doesn&apos;t recognize (
                  {lastResult.unmatchedTemplateFields.length})
                </div>
                <p className="text-xs text-muted-foreground">
                  These won&apos;t be filled. Rename them in the Documenso template editor to match
                  a CRM-expected label (Name, Email, Address, Yacht Name, Length, Width, Draft,
                  Berth Number, Lease_10, Purchase), or ignore if they&apos;re signature/date fields
                  the recipient fills in themselves.
                </p>
                <div className="flex flex-wrap gap-1.5 pt-1">
                  {lastResult.unmatchedTemplateFields.map((f) => (
                    <span
                      key={f.fieldId}
                      className="rounded bg-amber-100 px-1.5 py-0.5 font-mono text-xs text-amber-900 dark:bg-amber-950 dark:text-amber-200"
                    >
                      {f.label} → #{f.fieldId}
                    </span>
                  ))}
                </div>
              </div>
            )}

            {lastResult.acroForm.length > 0 && (
              <div className="pt-2.5 border-t border-emerald-200/60 dark:border-emerald-900/40">
                <div className="font-medium text-foreground">
                  PDF AcroForm fields (the <code>formValues</code> path)
                </div>
                <p className="pt-0.5 text-xs text-muted-foreground">
                  These are the fillable fields actually in the PDF binary on Documenso. The CRM
                  fills them by name at send time - this is the same mechanism the prod v1 server
                  uses.
                </p>
                {lastResult.acroForm.map((report) => (
                  <div key={report.envelopeItemId} className="mt-1.5 space-y-1">
                    {report.error ? (
                      <div className="rounded bg-destructive/10 px-2 py-1 text-xs text-destructive">
                        Couldn&apos;t inspect this PDF: {report.error}
                      </div>
                    ) : report.fields.length === 0 ? (
                      <div className="rounded bg-amber-100 px-2 py-1 text-xs text-amber-900 dark:bg-amber-950 dark:text-amber-200">
                        <AlertTriangle
                          className="mr-1 inline h-3.5 w-3.5 align-text-bottom"
                          aria-hidden
                        />
                        This PDF has no AcroForm fields. The CRM&apos;s <code>formValues</code> path
                        will fill nothing. Re-export your PDF with form fields enabled, or place
                        overlays inside Documenso&apos;s editor and use <code>prefillFields</code>{' '}
                        instead.
                      </div>
                    ) : (
                      <>
                        {report.matchedFieldNames.length > 0 && (
                          <div>
                            <div className="font-medium text-emerald-700 dark:text-emerald-400">
                              ✓ CRM-fillable AcroForm fields ({report.matchedFieldNames.length})
                            </div>
                            <div className="flex flex-wrap gap-1.5 pt-0.5">
                              {report.matchedFieldNames.map((n) => (
                                <span
                                  key={n}
                                  className="rounded bg-emerald-100 px-1.5 py-0.5 font-mono text-xs text-emerald-900 dark:bg-emerald-950 dark:text-emerald-200"
                                >
                                  {n}
                                </span>
                              ))}
                            </div>
                          </div>
                        )}
                        {report.missingFieldNames.length > 0 && (
                          <div>
                            <div className="font-medium text-amber-700 dark:text-amber-400">
                              ⚠️ CRM tokens missing from the PDF ({report.missingFieldNames.length})
                            </div>
                            <p className="text-xs text-muted-foreground">
                              These exact names need AcroForm text/checkbox fields in the PDF, or
                              they&apos;ll be dropped at send time.
                            </p>
                            <div className="flex flex-wrap gap-1.5 pt-0.5">
                              {report.missingFieldNames.map((n) => (
                                <span
                                  key={n}
                                  className="rounded bg-amber-100 px-1.5 py-0.5 font-mono text-xs text-amber-900 dark:bg-amber-950 dark:text-amber-200"
                                >
                                  {n}
                                </span>
                              ))}
                            </div>
                          </div>
                        )}
                        {report.extraFieldNames.length > 0 && (
                          <div>
                            <div className="font-medium text-muted-foreground">
                              PDF fields the CRM has no token for ({report.extraFieldNames.length})
                            </div>
                            <p className="text-xs text-muted-foreground">
                              Usually signature blocks or other fields the recipient fills in
                              directly. Safe to ignore.
                            </p>
                            <div className="flex flex-wrap gap-1.5 pt-0.5">
                              {report.extraFieldNames.map((n) => (
                                <span
                                  key={n}
                                  className="rounded bg-muted px-1.5 py-0.5 font-mono text-xs text-muted-foreground"
                                >
                                  {n}
                                </span>
                              ))}
                            </div>
                          </div>
                        )}
                      </>
                    )}
                  </div>
                ))}
              </div>
            )}

            {lastResult.fieldCount > 0 && lastResult.missingFromTemplate.length > 0 && (
              <div className="pt-1.5">
                <div className="font-medium text-muted-foreground">
                  CRM data points not in <code>prefillFields</code> (
                  {lastResult.missingFromTemplate.length})
                </div>
                <p className="text-xs text-muted-foreground">
                  These would also be available as <code>prefillFields</code> if you added matching
                  overlays inside Documenso&apos;s template editor.
                </p>
                <div className="flex flex-wrap gap-1.5 pt-1">
                  {lastResult.missingFromTemplate.map((label) => (
                    <span
                      key={label}
                      className="rounded bg-muted px-1.5 py-0.5 font-mono text-xs text-muted-foreground"
                    >
                      {label}
                    </span>
                  ))}
                </div>
              </div>
            )}
          </div>
        </div>
      )}

      {sync.isError && !lastResult && (
        <div className="rounded-md border border-destructive/40 bg-destructive/5 p-3 text-xs">
          <div className="flex items-center gap-2 font-medium text-destructive">
            <XCircle className="size-3" /> Sync failed - check the Documenso credentials above and
            confirm the template exists on the configured instance.
          </div>
        </div>
      )}
    </div>
  );
}
