'use client';

import { useMemo, useRef, useState } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { Document, Page, pdfjs } from 'react-pdf';
import { Loader2, Save, Trash2, X } from 'lucide-react';

import 'react-pdf/dist/Page/AnnotationLayer.css';
import 'react-pdf/dist/Page/TextLayer.css';

import { Button } from '@/components/ui/button';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Label } from '@/components/ui/label';
import { PageHeader } from '@/components/shared/page-header';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';
import { VALID_MERGE_TOKENS } from '@/lib/templates/merge-fields';
import type { FieldMap, FieldMapEntry } from '@/lib/templates/field-map';

// Worker setup mirrors src/components/files/pdf-viewer.tsx so we don't
// pay for a second bundle. Calling GlobalWorkerOptions.workerSrc twice
// with the same URL is a no-op in pdfjs.
pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;

interface TemplateData {
  id: string;
  name: string;
  templateType: string;
  templateFormat: string;
  sourceFileId: string | null;
  overlayPositions: FieldMap | null;
}

interface PendingMarker {
  x: number;
  y: number;
  page: number;
}

const TOKEN_OPTIONS = Array.from(VALID_MERGE_TOKENS).sort();
const DEFAULT_MARKER_W = 0.18;
const DEFAULT_MARKER_H = 0.04;

/**
 * Phase 7.1 — page-1 PDF marker editor. Click anywhere on the rendered
 * PDF to drop a marker, pick which merge token it represents, save.
 *
 * Scope intentionally narrow:
 *  - Page 1 only (multi-page page-picker is a 7.2 ticket).
 *  - Add + delete markers; drag-to-move + corner-resize defer to 7.2.
 *  - Coordinates stored as percent of page width/height so a future
 *    page-size swap (A4 ↔ Letter) doesn't shift placements.
 */
export function TemplateEditor({ templateId }: { templateId: string }) {
  const { data: template, isLoading } = useQuery<{ data: TemplateData }>({
    queryKey: ['document-template', templateId],
    queryFn: () => apiFetch<{ data: TemplateData }>(`/api/v1/document-templates/${templateId}`),
  });

  if (isLoading || !template) {
    return (
      <div className="flex h-64 items-center justify-center text-sm text-muted-foreground">
        <Loader2 className="mr-2 h-4 w-4 animate-spin" />
        Loading template…
      </div>
    );
  }

  // Inner body keyed by templateId so a route change re-mounts and
  // the markers useState initializer re-reads the server payload.
  // Avoids the in-render setState pattern (React anti-pattern) that
  // a single component would otherwise need to seed from the query.
  return <TemplateEditorBody key={templateId} templateId={templateId} template={template.data} />;
}

function TemplateEditorBody({
  templateId,
  template,
}: {
  templateId: string;
  template: TemplateData;
}) {
  const qc = useQueryClient();
  const [markers, setMarkers] = useState<FieldMap>(template.overlayPositions ?? []);
  const [pending, setPending] = useState<PendingMarker | null>(null);
  const [pendingToken, setPendingToken] = useState<string>('');
  const [saving, setSaving] = useState(false);
  const [savedMsg, setSavedMsg] = useState<string | null>(null);
  const pageContainerRef = useRef<HTMLDivElement | null>(null);

  const pdfUrl = template.sourceFileId ? `/api/v1/files/${template.sourceFileId}/preview` : null;

  function handlePageClick(e: React.MouseEvent<HTMLDivElement>) {
    const container = pageContainerRef.current;
    if (!container) return;
    const rect = container.getBoundingClientRect();
    const x = (e.clientX - rect.left) / rect.width;
    const y = (e.clientY - rect.top) / rect.height;
    if (x < 0 || x > 1 || y < 0 || y > 1) return;
    setPending({ x, y, page: 1 });
    setPendingToken(TOKEN_OPTIONS[0] ?? '');
  }

  function commitPending() {
    if (!pending || !pendingToken) return;
    const entry: FieldMapEntry = {
      token: pendingToken,
      page: pending.page,
      x: pending.x,
      y: pending.y,
      w: DEFAULT_MARKER_W,
      h: DEFAULT_MARKER_H,
    };
    setMarkers((m) => [...m, entry]);
    setPending(null);
    setPendingToken('');
  }

  function cancelPending() {
    setPending(null);
    setPendingToken('');
  }

  function removeMarker(index: number) {
    setMarkers((m) => m.filter((_, i) => i !== index));
  }

  async function save() {
    setSaving(true);
    setSavedMsg(null);
    try {
      await apiFetch(`/api/v1/document-templates/${templateId}`, {
        method: 'PATCH',
        body: { overlayPositions: markers },
      });
      await qc.invalidateQueries({ queryKey: ['document-template', templateId] });
      setSavedMsg('Markers saved.');
    } catch (err) {
      toastError(err);
    } finally {
      setSaving(false);
    }
  }

  const visibleMarkers = useMemo(() => markers.filter((m) => m.page === 1), [markers]);

  if (!pdfUrl) {
    return (
      <div className="space-y-4">
        <PageHeader
          title={`Edit "${template.name}"`}
          description="Place merge-field markers on the source PDF."
        />
        <Card>
          <CardContent className="py-10 text-center text-sm text-muted-foreground">
            This template has no source PDF attached. Upload one from the template list before
            opening the editor.
          </CardContent>
        </Card>
      </div>
    );
  }

  return (
    <div className="space-y-4">
      <PageHeader
        title={`Edit "${template.name}"`}
        description="Click anywhere on the page to drop a merge-field marker. Phase 1: page 1, click-to-place. Drag/resize/preview lands later."
      />

      <div className="grid gap-4 lg:grid-cols-[1fr_320px]">
        <Card>
          <CardHeader className="pb-2">
            <CardTitle className="text-sm">Page 1</CardTitle>
          </CardHeader>
          <CardContent>
            {/* Wrapper carries the click handler. react-pdf renders the
                actual page inside; we overlay markers as positioned
                divs using the same percent coordinates the server-side
                fill path consumes. */}
            <div
              ref={pageContainerRef}
              onClick={handlePageClick}
              className="relative inline-block cursor-crosshair select-none"
            >
              <Document
                file={pdfUrl}
                loading={
                  <div className="flex items-center gap-2 p-6 text-sm text-muted-foreground">
                    <Loader2 className="h-4 w-4 animate-spin" />
                    Loading PDF…
                  </div>
                }
                onLoadError={(err) => {
                  // Surface load errors via toast rather than blowing up
                  // — a bad source PDF shouldn't crash the editor shell.
                  toastError(err);
                }}
              >
                <Page
                  pageNumber={1}
                  width={680}
                  renderAnnotationLayer={false}
                  renderTextLayer={false}
                />
              </Document>

              {visibleMarkers.map((m, i) => (
                <div
                  key={i}
                  style={{
                    position: 'absolute',
                    left: `${m.x * 100}%`,
                    top: `${m.y * 100}%`,
                    width: `${(m.w ?? DEFAULT_MARKER_W) * 100}%`,
                    height: `${(m.h ?? DEFAULT_MARKER_H) * 100}%`,
                  }}
                  className="pointer-events-none rounded border-2 border-primary/70 bg-primary/15 px-1 py-0.5 text-[10px] font-medium text-primary"
                >
                  {m.token}
                </div>
              ))}

              {pending ? (
                <div
                  style={{
                    position: 'absolute',
                    left: `${pending.x * 100}%`,
                    top: `${pending.y * 100}%`,
                    width: `${DEFAULT_MARKER_W * 100}%`,
                    height: `${DEFAULT_MARKER_H * 100}%`,
                  }}
                  className="pointer-events-none rounded border-2 border-amber-500 bg-amber-500/15"
                />
              ) : null}
            </div>
          </CardContent>
        </Card>

        <div className="space-y-4">
          {pending ? (
            <Card>
              <CardHeader className="pb-2">
                <CardTitle className="text-sm">New marker</CardTitle>
              </CardHeader>
              <CardContent className="space-y-3">
                <div className="space-y-1">
                  <Label className="text-xs">Merge token</Label>
                  <Select value={pendingToken} onValueChange={setPendingToken}>
                    <SelectTrigger>
                      <SelectValue placeholder="Pick a token…" />
                    </SelectTrigger>
                    <SelectContent className="max-h-72">
                      {TOKEN_OPTIONS.map((t) => (
                        <SelectItem key={t} value={t}>
                          {t}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
                <div className="flex justify-between gap-2">
                  <Button variant="outline" size="sm" onClick={cancelPending}>
                    <X className="mr-1.5 h-3.5 w-3.5" /> Cancel
                  </Button>
                  <Button size="sm" disabled={!pendingToken} onClick={commitPending}>
                    Add marker
                  </Button>
                </div>
              </CardContent>
            </Card>
          ) : null}

          <Card>
            <CardHeader className="pb-2">
              <CardTitle className="text-sm">Markers ({visibleMarkers.length})</CardTitle>
            </CardHeader>
            <CardContent className="space-y-2">
              {visibleMarkers.length === 0 ? (
                <p className="text-xs text-muted-foreground">
                  Click on the PDF to drop your first marker.
                </p>
              ) : (
                visibleMarkers.map((m, i) => (
                  <div
                    key={i}
                    className="flex items-center justify-between gap-2 rounded border px-2 py-1 text-xs"
                  >
                    <span className="font-mono">{m.token}</span>
                    <button
                      type="button"
                      onClick={() => removeMarker(markers.indexOf(m))}
                      className="text-muted-foreground hover:text-destructive"
                      aria-label={`Remove ${m.token} marker`}
                    >
                      <Trash2 className="h-3.5 w-3.5" />
                    </button>
                  </div>
                ))
              )}
            </CardContent>
          </Card>

          <Button onClick={save} disabled={saving} className="w-full">
            <Save className="mr-1.5 h-4 w-4" />
            {saving ? 'Saving…' : 'Save markers'}
          </Button>
          {savedMsg ? <p className="text-center text-xs text-emerald-700">{savedMsg}</p> : null}
        </div>
      </div>
    </div>
  );
}
