'use client';

/**
 * DocumentEditor — a Google-Docs-like editor over typed document sub-sections.
 *
 * The reusable surface a tenant app uses to review + edit a multi-part content
 * record (e.g. a marketing draft = blog markdown + LinkedIn text + SEO fields +
 * sources). Generic + schema-driven (see `./sections`), presentational, and
 * CONTROLLED: the parent owns the section values (via `onChange`) and all
 * persistence (`onSave` is debounced autosave — bring your own writer). It never
 * fetches. Complements the read-only DraftReviewWorkspace.
 */
import * as React from 'react';
import { Columns2, Eye, Pencil, Plus, Trash2, Loader2, Check, AlertCircle } from 'lucide-react';

import { cn } from '../../lib/utils';
import { MarkdownRenderer } from '../blog/MarkdownRenderer';
import type { DocSection } from './types';

export type SaveStatus = 'idle' | 'saving' | 'saved' | 'error';

export interface DocumentEditorProps {
  sections: DocSection[];
  /** Controlled per-section edit — the parent updates its section state. */
  onChange?(key: string, value: unknown): void;
  /** Debounced autosave (BYO persistence). Receives the current sections. */
  onSave?(sections: DocSection[]): void | Promise<void>;
  /** Autosave debounce, ms. Default 1200. */
  autosaveMs?: number;
  /** Render every section read-only (previews only). */
  readOnly?: boolean;
  /** Title / actions slot rendered in the header bar (e.g. a "Mark ready" button). */
  header?: React.ReactNode;
  className?: string;
}

function countWords(s: string): number {
  const t = s.trim();
  return t ? t.split(/\s+/).length : 0;
}

function asString(v: unknown): string {
  return typeof v === 'string' ? v : v == null ? '' : String(v);
}
function asRecord(v: unknown): Record<string, string> {
  if (v && typeof v === 'object' && !Array.isArray(v)) {
    const out: Record<string, string> = {};
    for (const [k, val] of Object.entries(v as Record<string, unknown>)) out[k] = asString(val);
    return out;
  }
  return {};
}
function asList(v: unknown): string[] {
  return Array.isArray(v) ? v.map(asString) : [];
}

/** A key like `meta_description` / `metaDescription` → an SEO description meter. */
function isMetaDescriptionKey(key: string): boolean {
  return /meta[_-]?description/i.test(key) || /^description$/i.test(key);
}

export function DocumentEditor({
  sections,
  onChange,
  onSave,
  autosaveMs = 1200,
  readOnly = false,
  header,
  className,
}: DocumentEditorProps) {
  const [status, setStatus] = React.useState<SaveStatus>('idle');

  // Serialize the section values so autosave fires only on a real content change.
  const serialized = React.useMemo(
    () => JSON.stringify(sections.map((s) => [s.key, s.value])),
    [sections],
  );

  // Keep latest sections + onSave in refs so the debounce effect depends only on
  // the serialized content (not on a fresh inline `onSave` identity each render).
  const sectionsRef = React.useRef(sections);
  sectionsRef.current = sections;
  const onSaveRef = React.useRef(onSave);
  onSaveRef.current = onSave;
  const savedRef = React.useRef(serialized);

  React.useEffect(() => {
    if (readOnly) return;
    const fn = onSaveRef.current;
    if (!fn) return;
    if (serialized === savedRef.current) return;

    let cancelled = false;
    const timer = setTimeout(async () => {
      setStatus('saving');
      try {
        await fn(sectionsRef.current);
        if (cancelled) return;
        savedRef.current = serialized;
        setStatus('saved');
      } catch {
        if (!cancelled) setStatus('error');
      }
    }, autosaveMs);

    return () => {
      cancelled = true;
      clearTimeout(timer);
    };
  }, [serialized, readOnly, autosaveMs]);

  const showBar = header != null || (!readOnly && !!onSave);

  return (
    <div className={cn('space-y-5', className)}>
      {showBar && (
        <div className="flex flex-wrap items-center justify-between gap-3">
          <div className="min-w-0">{header}</div>
          {!readOnly && onSave && <SaveStatusPill status={status} />}
        </div>
      )}

      <div className="space-y-6">
        {sections.map((section) => (
          <SectionEditor
            key={section.key}
            section={section}
            readOnly={readOnly || !!section.readOnly}
            onChange={onChange}
          />
        ))}
      </div>
    </div>
  );
}

function SaveStatusPill({ status }: { status: SaveStatus }) {
  const map: Record<SaveStatus, { label: string; tone: string; icon: React.ReactNode }> = {
    idle: { label: '', tone: 'text-muted-foreground', icon: null },
    saving: { label: 'Saving…', tone: 'text-muted-foreground', icon: <Loader2 className="h-3 w-3 animate-spin" /> },
    saved: { label: 'Saved', tone: 'text-emerald-600', icon: <Check className="h-3 w-3" /> },
    error: { label: 'Save failed', tone: 'text-rose-600', icon: <AlertCircle className="h-3 w-3" /> },
  };
  const s = map[status];
  if (!s.label) return null;
  return (
    <span className={cn('inline-flex items-center gap-1.5 text-xs', s.tone)} role="status" aria-live="polite">
      {s.icon}
      {s.label}
    </span>
  );
}

function SectionEditor({
  section,
  readOnly,
  onChange,
}: {
  section: DocSection;
  readOnly: boolean;
  onChange?(key: string, value: unknown): void;
}) {
  const emit = React.useCallback((value: unknown) => onChange?.(section.key, value), [onChange, section.key]);

  return (
    <section className="rounded-lg border border-border bg-card">
      <SectionBody section={section} readOnly={readOnly} emit={emit} />
    </section>
  );
}

function SectionHeader({ section, right }: { section: DocSection; right?: React.ReactNode }) {
  return (
    <div className="flex items-center justify-between gap-2 border-b border-border px-4 py-2">
      <h3 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">{section.label}</h3>
      {right}
    </div>
  );
}

function SectionBody({
  section,
  readOnly,
  emit,
}: {
  section: DocSection;
  readOnly: boolean;
  emit: (value: unknown) => void;
}) {
  switch (section.kind) {
    case 'markdown':
      return <MarkdownSection section={section} readOnly={readOnly} emit={emit} />;
    case 'text':
      return <TextSection section={section} readOnly={readOnly} emit={emit} />;
    case 'structured':
      return <StructuredSection section={section} readOnly={readOnly} emit={emit} />;
    case 'list':
      return <ListSection section={section} readOnly={readOnly} emit={emit} />;
    default:
      return null;
  }
}

type ViewMode = 'edit' | 'preview' | 'split';

function MarkdownSection({
  section,
  readOnly,
  emit,
}: {
  section: DocSection;
  readOnly: boolean;
  emit: (value: unknown) => void;
}) {
  const value = asString(section.value);
  const [mode, setMode] = React.useState<ViewMode>('split');
  const words = countWords(value);

  if (readOnly) {
    return (
      <>
        <SectionHeader section={section} right={<span className="text-xs text-muted-foreground">{words} words</span>} />
        <div className="px-4 py-3">
          {value ? (
            <MarkdownRenderer content={value} />
          ) : (
            <p className="text-sm italic text-muted-foreground">Empty.</p>
          )}
        </div>
      </>
    );
  }

  const showEditor = mode === 'edit' || mode === 'split';
  const showPreview = mode === 'preview' || mode === 'split';

  return (
    <>
      <SectionHeader
        section={section}
        right={
          <div className="flex items-center gap-3">
            <span className="text-xs text-muted-foreground">{words} words</span>
            <ModeToggle mode={mode} onMode={setMode} />
          </div>
        }
      />
      <div className={cn('grid gap-0', mode === 'split' && 'lg:grid-cols-2 lg:divide-x lg:divide-border')}>
        {showEditor && (
          <textarea
            value={value}
            onChange={(e) => emit(e.target.value)}
            placeholder={section.placeholder}
            aria-label={`${section.label} markdown`}
            className="min-h-[16rem] w-full resize-y border-0 bg-transparent p-4 font-mono text-sm leading-relaxed text-foreground outline-none placeholder:text-muted-foreground focus:ring-0"
            spellCheck
          />
        )}
        {showPreview && (
          <div className="min-h-[16rem] overflow-x-auto p-4">
            {value ? (
              <MarkdownRenderer content={value} />
            ) : (
              <p className="text-sm italic text-muted-foreground">Nothing to preview yet.</p>
            )}
          </div>
        )}
      </div>
    </>
  );
}

function ModeToggle({ mode, onMode }: { mode: ViewMode; onMode: (m: ViewMode) => void }) {
  const opts: { value: ViewMode; label: string; icon: React.ReactNode; hideOnNarrow?: boolean }[] = [
    { value: 'edit', label: 'Edit', icon: <Pencil className="h-3 w-3" /> },
    { value: 'preview', label: 'Preview', icon: <Eye className="h-3 w-3" /> },
    { value: 'split', label: 'Split', icon: <Columns2 className="h-3 w-3" />, hideOnNarrow: true },
  ];
  return (
    <div className="inline-flex overflow-hidden rounded-md border border-border" role="group" aria-label="View mode">
      {opts.map((o) => (
        <button
          key={o.value}
          type="button"
          onClick={() => onMode(o.value)}
          aria-pressed={mode === o.value}
          className={cn(
            'inline-flex items-center gap-1 px-2 py-1 text-xs transition-colors',
            o.hideOnNarrow && 'hidden lg:inline-flex',
            mode === o.value ? 'bg-primary text-primary-foreground' : 'bg-transparent text-muted-foreground hover:bg-muted',
          )}
        >
          {o.icon}
          {o.label}
        </button>
      ))}
    </div>
  );
}

function TextSection({
  section,
  readOnly,
  emit,
}: {
  section: DocSection;
  readOnly: boolean;
  emit: (value: unknown) => void;
}) {
  const value = asString(section.value);
  const words = countWords(value);
  const chars = value.length;

  return (
    <>
      <SectionHeader
        section={section}
        right={
          <span className="text-xs text-muted-foreground">
            {words} words · {chars} chars
          </span>
        }
      />
      <div className="px-4 py-3">
        {readOnly ? (
          value ? (
            <p className="whitespace-pre-wrap text-sm text-foreground">{value}</p>
          ) : (
            <p className="text-sm italic text-muted-foreground">Empty.</p>
          )
        ) : (
          <textarea
            value={value}
            onChange={(e) => emit(e.target.value)}
            placeholder={section.placeholder}
            aria-label={section.label}
            className="min-h-[8rem] w-full resize-y rounded-md border border-border bg-background p-3 text-sm leading-relaxed text-foreground outline-none placeholder:text-muted-foreground focus:border-primary focus:ring-0"
            spellCheck
          />
        )}
      </div>
    </>
  );
}

function StructuredSection({
  section,
  readOnly,
  emit,
}: {
  section: DocSection;
  readOnly: boolean;
  emit: (value: unknown) => void;
}) {
  const obj = asRecord(section.value);
  const keys = Object.keys(obj);

  const setField = (field: string, val: string) => emit({ ...obj, [field]: val });

  return (
    <>
      <SectionHeader section={section} />
      <div className="space-y-3 px-4 py-3">
        {keys.length === 0 && <p className="text-sm italic text-muted-foreground">No fields.</p>}
        {keys.map((field) => {
          const fieldVal = obj[field];
          const meta = isMetaDescriptionKey(field);
          return (
            <div key={field} className="grid gap-1 sm:grid-cols-[10rem_minmax(0,1fr)] sm:items-start sm:gap-3">
              <label htmlFor={`${section.key}-${field}`} className="pt-1.5 text-xs font-medium text-muted-foreground">
                {field.replace(/[_-]+/g, ' ')}
              </label>
              <div>
                {readOnly ? (
                  <p className="text-sm text-foreground">{fieldVal || '—'}</p>
                ) : (
                  <input
                    id={`${section.key}-${field}`}
                    value={fieldVal}
                    onChange={(e) => setField(field, e.target.value)}
                    className="w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-sm text-foreground outline-none focus:border-primary focus:ring-0"
                  />
                )}
                {meta && <CharMeter value={fieldVal} good={[150, 160]} />}
              </div>
            </div>
          );
        })}
      </div>
    </>
  );
}

/** A subtle character-count meter with an optional "good" band hint (e.g. SEO meta 150–160). */
function CharMeter({ value, good }: { value: string; good: [number, number] }) {
  const len = value.length;
  const [lo, hi] = good;
  const tone = len === 0 ? 'text-muted-foreground' : len >= lo && len <= hi ? 'text-emerald-600' : 'text-amber-600';
  return (
    <p className={cn('mt-1 text-[11px]', tone)}>
      {len} chars{good ? ` · aim ${lo}–${hi}` : ''}
    </p>
  );
}

function ListSection({
  section,
  readOnly,
  emit,
}: {
  section: DocSection;
  readOnly: boolean;
  emit: (value: unknown) => void;
}) {
  const items = asList(section.value);

  const setItem = (i: number, val: string) => emit(items.map((it, idx) => (idx === i ? val : it)));
  const removeItem = (i: number) => emit(items.filter((_, idx) => idx !== i));
  const addItem = () => emit([...items, '']);

  if (readOnly) {
    return (
      <>
        <SectionHeader section={section} right={<span className="text-xs text-muted-foreground">{items.length}</span>} />
        <div className="px-4 py-3">
          {items.length === 0 ? (
            <p className="text-sm italic text-muted-foreground">None.</p>
          ) : (
            <ul className="list-disc space-y-1 pl-5 text-sm text-foreground">
              {items.map((it, i) => (
                <li key={i} className="break-words">
                  {it}
                </li>
              ))}
            </ul>
          )}
        </div>
      </>
    );
  }

  return (
    <>
      <SectionHeader section={section} right={<span className="text-xs text-muted-foreground">{items.length}</span>} />
      <div className="space-y-2 px-4 py-3">
        {items.map((it, i) => (
          <div key={i} className="flex items-center gap-2">
            <input
              value={it}
              onChange={(e) => setItem(i, e.target.value)}
              placeholder={section.placeholder}
              aria-label={`${section.label} item ${i + 1}`}
              className="w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-sm text-foreground outline-none focus:border-primary focus:ring-0"
            />
            <button
              type="button"
              onClick={() => removeItem(i)}
              aria-label={`Remove item ${i + 1}`}
              className="shrink-0 rounded-md p-1.5 text-muted-foreground hover:bg-muted hover:text-rose-600"
            >
              <Trash2 className="h-4 w-4" />
            </button>
          </div>
        ))}
        <button
          type="button"
          onClick={addItem}
          className="inline-flex items-center gap-1 rounded-md border border-dashed border-border px-2.5 py-1.5 text-xs text-muted-foreground hover:border-primary hover:text-foreground"
        >
          <Plus className="h-3.5 w-3.5" />
          Add
        </button>
      </div>
    </>
  );
}
