import type { FunctionalComponent } from 'preact';
import { useEffect, useMemo, useState } from 'preact/hooks';
import { registerModule } from '../../core/modules';
import type { AsukaModuleContext } from '../../core/modules';
import { useAsukaStore } from '../../store/asukaStore';
import { Button } from '../core/Button';
import { Card, CardContent, CardTitle } from '../core/Card';
import { Field } from '../core/Field';
import { Select } from '../core/Select';
import { useT } from '../../hooks/useT';
import { ensureFontFamilyLoaded } from '../../core/fontRegistry';

export const TextCreateModule: FunctionalComponent<{ context?: AsukaModuleContext; onDone?: () => void }> = ({ context, onDone }) => {
  const t = useT();
  const engine = context?.getEngine?.() ?? null;
  const activeRenderEngineKind = useAsukaStore((s: any) => s.activeRenderEngineKind ?? 'fabric');
  const activeId = useAsukaStore((s) => s.fixedSlotActiveId);
  const storedSlots = useAsukaStore((s) => s.fixedSlots);
  const close = useAsukaStore((s) => s.closeModule);
  const fontsCatalog = useAsukaStore((s: any) => s.fontsCatalog ?? []);

  const slot = useMemo(() => (storedSlots ?? []).find((x: any) => x.id === activeId) ?? null, [storedSlots, activeId]);

  const [text, setText] = useState('');
  const [fontFamily, setFontFamily] = useState('Arial');
  const [err, setErr] = useState<string | null>(null);

  useEffect(() => {
    setErr(null);
  }, [activeId]);

  const info = useMemo(() => {
    const c: any = (slot as any)?.constraints ?? {};
    return {
      minChars: typeof c.minChars === 'number' ? c.minChars : 0,
      maxChars: typeof c.maxChars === 'number' ? c.maxChars : null,
      maxLines: typeof c.maxLines === 'number' ? c.maxLines : null,
      allowedFonts: Array.isArray(c.allowedFonts) ? c.allowedFonts.map((value: unknown) => String(value ?? '').trim()).filter(Boolean) : [],
    };
  }, [slot]);

  const fontOptions = useMemo(() => {
    const allowed = new Set(info.allowedFonts.map((family: string) => family.toLowerCase()));
    const families = (Array.isArray(fontsCatalog) ? fontsCatalog : [])
      .map((font: any) => String(font?.family ?? '').trim())
      .filter((family: string) => family && (!allowed.size || allowed.has(family.toLowerCase())));
    if (!families.some((family: string) => family.toLowerCase() === fontFamily.toLowerCase())) {
      families.unshift(info.allowedFonts[0] || fontFamily);
    }
    return Array.from(new Set(families)).filter(Boolean).map((family) => ({ value: family, label: family }));
  }, [fontFamily, fontsCatalog, info.allowedFonts]);

  useEffect(() => {
    if (fontOptions.length && !fontOptions.some((option) => option.value === fontFamily)) {
      setFontFamily(fontOptions[0].value);
    }
  }, [fontFamily, fontOptions]);

  const apply = async () => {
    setErr(null);
    if (!engine) return;

    const usingSlot = !!slot && slot.type === 'text';
    const minChars = usingSlot ? (info.minChars ?? 0) : 0;
    const trimmed = text.trim();
    const lines = text.length === 0 ? 0 : String(text).split(/\r?\n/).length;

    if (trimmed.length < minChars) {
      setErr(`Minimum ${minChars} characters.`);
      return;
    }

    if (usingSlot && info.maxChars != null && trimmed.length > info.maxChars) {
      setErr(`Maximum ${info.maxChars} characters.`);
      return;
    }

    if (usingSlot && info.maxLines != null && lines > info.maxLines) {
      setErr(`Maximum ${info.maxLines} lines.`);
      return;
    }

    // If multiple drawing areas exist, let the active renderer pick the target area.
    let printAreaId: string | null = null;
    try { printAreaId = await engine.areas?.pickForAdd() ?? null; } catch {}

    await ensureFontFamilyLoaded(fontFamily);

    await engine.objects.addText({
      text,
      fontFamily,
      fontSize: activeRenderEngineKind === '3d' ? 72 : 22,
      color: '#111827',
      fill: '#111827',
      printAreaId,
      targetPrintAreaId: printAreaId,
      metadata: { sourceModule: 'text', printAreaId, targetPrintAreaId: printAreaId },
    } as any);
    if (onDone) onDone();
    else close?.();
  };

  return (
    <div className="ask-flex ask-flex-col ask-gap-4">
      <Card>
        <CardContent>
          <CardTitle>{t('text.createText', 'Create text')}</CardTitle>
          <div className="ask-text-[11px] ask-text-textMuted ask-mt-1">
            {slot && slot.type === 'text'
              ? `Slot: ${slot.label || slot.id}`
              : t('text.clickPlaceholderToCreate', 'Click a text placeholder on the canvas to create text here.')}
          </div>

          <div className="ask-mt-3 ask-flex ask-flex-col ask-gap-2">
            <Field
              label={t('modules.text', 'Text')}
              required
              hint={
                info.maxChars != null || info.maxLines != null
                  ? `Constraints: ${info.maxChars != null ? `max ${info.maxChars} chars` : ''}${
                      info.maxChars != null && info.maxLines != null ? ' • ' : ''
                    }${info.maxLines != null ? `max ${info.maxLines} lines` : ''}`
                  : undefined
              }
            >
              <textarea
                required
                aria-required="true"
                value={text}
                onInput={(e) => setText((e.currentTarget as HTMLTextAreaElement).value)}
                placeholder={t('text.typeYourText', 'Type your text...')}
                rows={6}
                className="ask-theme-input ask-w-full ask-rounded-[12px] ask-border ask-px-3 ask-py-2 ask-text-[13px] ask-leading-5 ask-min-h-[140px] ask-resize-y"
              />
            </Field>

            <Field label={t('ui.font', 'Font')}>
              <Select value={fontFamily} options={fontOptions} onChange={(event) => setFontFamily((event.currentTarget as HTMLSelectElement).value)} />
            </Field>

            {err ? <div className="ask-text-[12px] ask-text-danger">{err}</div> : null}

            <div className="ask-flex ask-items-center ask-gap-2">
              <Button variant="primary" onClick={apply}>
                {t('ui.add_to_canvas', 'Add to canvas')}
              </Button>
              <Button variant="secondary" onClick={() => close?.()}>
                Close
              </Button>
            </div>
          </div>
        </CardContent>
      </Card>
    </div>
  );
};

registerModule({
  id: 'text' as any,
  label: 'Text',
  icon: 'text',
  displayMode: 'floating',
  supportedEngines: ['fabric', '3d'],
  requiredCapabilities: ['addText'],
  render: (props: any) => <TextCreateModule context={props?.context} />,
});
