// EditorPanel — the designer's right-hand controls: card-level options
// (scrim, name, default) and per-selection editing (font, size, rotation,
// style preset + params; insert width/border; QSO box geometry).

import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
} from '@/components/ui/select';
import { Separator } from '@/components/ui/separator';
import { cn } from '@/lib/utils';
import { QSO_BOX_FIELDS, QSO_FIELD_LABELS } from './qslTypes';
import type { CardTemplate, CardElement, QSOBox, QSLPresetInfo, StyleParams } from './qslTypes';
import type { CardSelection } from './CardPreview';
import { StylePresetPicker, NumberField } from './StylePresetPicker';

interface Props {
  template: CardTemplate;
  sel: CardSelection;
  presets: QSLPresetInfo[];
  fontFamilies: string[]; // embedded + detected system faces
  onPatchElement: (idx: number, patch: Partial<CardElement>) => void;
  onPatchBox: (patch: Partial<QSOBox>) => void;
  onScrim: (enabled: boolean) => void;
  onSelect?: (sel: CardSelection) => void;
}

const TYPE_LABELS: Record<string, string> = {
  callsign: 'Callsign',
  operator: 'Operator name',
  info_line: 'Info line',
  country: 'Country + flag',
  insert: 'Photo insert',
};

// A readable layer name, disambiguating the two info lines and numbering inserts.
function layerLabel(el: CardElement, i: number, all: CardElement[]): string {
  if (el.type === 'info_line') {
    return /rig|antenna|ant\b/i.test(el.text ?? '') ? 'Station (rig / ant)' : 'Info line (zones)';
  }
  if (el.type === 'insert') {
    const n = all.slice(0, i + 1).filter((x) => x.type === 'insert').length;
    return `Photo insert ${n}`;
  }
  return TYPE_LABELS[el.type] ?? el.type;
}

function TextControls({ e, idx, presets, fontFamilies, onPatch }: {
  e: CardElement; idx: number; presets: QSLPresetInfo[]; fontFamilies: string[];
  onPatch: (idx: number, patch: Partial<CardElement>) => void;
}) {
  return (
    <div className="space-y-2">
      <div className="flex items-center justify-between gap-2">
        <Label className="text-xs text-muted-foreground">Font</Label>
        <Select value={e.font} onValueChange={(font) => onPatch(idx, { font })}>
          <SelectTrigger className="h-8 w-44">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {fontFamilies.map((f) => (
              <SelectItem key={f} value={f}>{f === 'system-bold-sans' ? 'System bold' : f}</SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>
      <NumberField label="Size" value={e.size ?? 0} min={8} max={500}
        onChange={(size) => onPatch(idx, { size })} />
      <NumberField label="Rotation °" value={e.rotate ?? 0} min={-45} max={45}
        onChange={(rotate) => onPatch(idx, { rotate })} />
      <div className="flex items-center justify-between gap-2">
        <Label className="text-xs text-muted-foreground">Text</Label>
        <Input className="h-7 w-44 font-mono text-xs" value={e.text ?? ''}
          onChange={(ev) => onPatch(idx, { text: ev.target.value })} />
      </div>
      <Separator className="my-2" />
      <StylePresetPicker
        presets={presets}
        preset={e.style_preset ?? 'flat_modern'}
        params={e.style_params ?? {}}
        onChange={(style_preset, style_params: StyleParams) =>
          onPatch(idx, { style_preset, style_params })}
      />
    </div>
  );
}

export function EditorPanel({ template, sel, presets, fontFamilies, onPatchElement, onPatchBox, onScrim, onSelect }: Props) {
  const e = typeof sel === 'number' ? template.elements[sel] : undefined;
  const box = template.qso_box;

  return (
    <div className="flex w-80 shrink-0 flex-col gap-3 overflow-y-auto pr-1 text-sm">
      <div className="space-y-2 rounded-md border border-border p-3">
        <div className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Card</div>
        <label className="flex items-center gap-2 text-sm">
          <Checkbox
            checked={!!template.hero.scrim?.enabled}
            onCheckedChange={(v) => onScrim(v === true)}
          />
          Darken photo behind text (scrim)
        </label>
      </div>

      {/* Layers: show/hide each piece, click a name to edit it. */}
      <div className="space-y-1 rounded-md border border-border p-3">
        <div className="mb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Show on card</div>
        {template.elements.map((el, i) => (
          <div key={i} className={cn('flex items-center gap-2 rounded px-1 py-0.5', sel === i && 'bg-muted')}>
            <Checkbox checked={!el.hidden} onCheckedChange={(v) => onPatchElement(i, { hidden: v !== true })} />
            <button type="button" className="flex-1 truncate text-left text-sm" onClick={() => onSelect?.(i)}>
              {layerLabel(el, i, template.elements)}
            </button>
          </div>
        ))}
        {box && (
          <div className={cn('flex items-center gap-2 rounded px-1 py-0.5', sel === 'box' && 'bg-muted')}>
            <Checkbox checked={box.enabled} onCheckedChange={(v) => onPatchBox({ enabled: v === true })} />
            <button type="button" className="flex-1 truncate text-left text-sm" onClick={() => onSelect?.('box')}>
              QSO info box
            </button>
          </div>
        )}
      </div>

      <div className="space-y-2 rounded-md border border-border p-3">
        <div className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
          {e ? TYPE_LABELS[e.type] ?? e.type : sel === 'box' ? 'QSO box' : 'Selection'}
        </div>
        {!e && sel !== 'box' && (
          <p className="text-xs text-muted-foreground">
            Click an element on the card to edit it; drag to move it.
          </p>
        )}

        {e && (e.type === 'callsign' || e.type === 'operator' || e.type === 'info_line') && (
          <TextControls e={e} idx={sel as number} presets={presets}
            fontFamilies={fontFamilies} onPatch={onPatchElement} />
        )}

        {e && e.type === 'insert' && (
          <div className="space-y-2">
            <NumberField label="Width" value={e.w ?? 0} min={80} max={1200}
              onChange={(w) => onPatchElement(sel as number, { w })} />
            <NumberField label="Border" value={e.border_px ?? 0} min={0} max={40}
              onChange={(border_px) => onPatchElement(sel as number, { border_px })} />
            <NumberField label="Rotation °" value={e.rotate ?? 0} min={-15} max={15}
              onChange={(rotate) => onPatchElement(sel as number, { rotate })} />
            <label className="flex items-center gap-2 text-sm">
              <Checkbox checked={!!e.shadow}
                onCheckedChange={(v) => onPatchElement(sel as number, { shadow: v === true })} />
              Drop shadow
            </label>
          </div>
        )}

        {e && e.type === 'country' && (
          <NumberField label="Size" value={e.size ?? 30} min={16} max={80}
            onChange={(size) => onPatchElement(sel as number, { size })} />
        )}

        {sel === 'box' && box && (
          <div className="space-y-2">
            <label className="flex items-center gap-2 text-sm">
              <Checkbox checked={box.enabled}
                onCheckedChange={(v) => onPatchBox({ enabled: v === true })} />
              Show QSO box
            </label>
            <NumberField label="Width" value={box.w} min={300} max={1400}
              onChange={(w) => onPatchBox({ w })} />
            <NumberField label="Height" value={box.h} min={120} max={500}
              onChange={(h) => onPatchBox({ h })} />
            <NumberField label="Opacity %" value={Math.round((box.bg_opacity ?? 1) * 100)} min={0} max={100}
              onChange={(v) => onPatchBox({ bg_opacity: Math.max(0, Math.min(100, v)) / 100 })} />
            <div className="flex items-center justify-between gap-2">
              <Label className="text-xs text-muted-foreground">Background</Label>
              <div className="flex items-center gap-2">
                <input type="color" className="h-7 w-9 cursor-pointer rounded border border-border bg-transparent p-0"
                  value={/^#[0-9a-fA-F]{6}$/.test(box.bg ?? '') ? box.bg : '#000000'}
                  onChange={(ev) => onPatchBox({ bg: ev.target.value })} />
                <Input className="h-7 w-32 font-mono text-xs" value={box.bg ?? ''}
                  onChange={(ev) => onPatchBox({ bg: ev.target.value })} />
              </div>
            </div>
            <div className="flex items-center justify-between gap-2">
              <Label className="text-xs text-muted-foreground">Text color</Label>
              <div className="flex items-center gap-2">
                <input type="color" className="h-7 w-9 cursor-pointer rounded border border-border bg-transparent p-0"
                  value={/^#[0-9a-fA-F]{6}$/.test(box.fg ?? '') ? (box.fg as string) : '#14243a'}
                  onChange={(ev) => onPatchBox({ fg: ev.target.value })} />
                <Input className="h-7 w-32 font-mono text-xs" value={box.fg ?? ''} placeholder="#14243a"
                  onChange={(ev) => onPatchBox({ fg: ev.target.value })} />
              </div>
            </div>
            <NumberField label="Corner radius" value={box.radius ?? 0} min={0} max={80}
              onChange={(radius) => onPatchBox({ radius })} />
            <div className="flex items-center justify-between gap-2">
              <Label className="text-xs text-muted-foreground">Title</Label>
              <Input className="h-7 w-44 font-mono text-xs" value={box.title ?? ''}
                onChange={(ev) => onPatchBox({ title: ev.target.value })} />
            </div>
            <div className="space-y-1">
              <Label className="text-xs text-muted-foreground">Columns</Label>
              {/* Rebuilt from the canonical order every time rather than
                  appended to: a box whose columns come out in the order they
                  were ticked reads as a bug, and the widths are tuned for this
                  order. */}
              <div className="grid grid-cols-2 gap-x-2">
                {QSO_BOX_FIELDS.map((f) => (
                  <label key={f} className="flex items-center gap-1.5 text-xs">
                    <Checkbox
                      checked={box.fields.includes(f)}
                      onCheckedChange={(v) => onPatchBox({
                        fields: QSO_BOX_FIELDS.filter((k) => (k === f ? v === true : box.fields.includes(k))),
                      })}
                    />
                    {QSO_FIELD_LABELS[f] ?? f}
                  </label>
                ))}
              </div>
            </div>
            <div className="flex items-center justify-between gap-2">
              <Label className="text-xs text-muted-foreground">Footer</Label>
              <Input className="h-7 w-44 font-mono text-xs" value={box.footer}
                onChange={(ev) => onPatchBox({ footer: ev.target.value })} />
            </div>
          </div>
        )}
      </div>

      <p className="px-1 text-[11px] leading-snug text-muted-foreground">
        Text supports {'{profile.*}'} and {'{qso.*}'} placeholders — they fill in
        automatically on every card.
      </p>
    </div>
  );
}
