import {
  createBibFieldEdit,
  getBibField,
  parseBibTeX,
} from '@learnitive/bibliography';
import { useCoreServices } from '@learnitive/context';
import { Button, Input, Label, toast } from '@learnitive/ui-components';
import React from 'react';

const PRIMARY_FIELDS = ['title', 'author', 'year', 'journal', 'booktitle', 'publisher', 'doi', 'url'] as const;

export function BibliographyVisualEditor({ wsPath }: { wsPath: string }) {
  const { latexSource } = useCoreServices();
  const [, rerender] = React.useReducer((value) => value + 1, 0);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState<string>();

  React.useEffect(() => latexSource.subscribe(wsPath, rerender), [latexSource, wsPath]);
  React.useEffect(() => {
    let cancelled = false;
    setLoading(true);
    void latexSource.load(wsPath).then(() => {
      if (!cancelled) setLoading(false);
    }).catch((reason) => {
      if (!cancelled) {
        setError(reason instanceof Error ? reason.message : String(reason));
        setLoading(false);
      }
    });
    return () => { cancelled = true; };
  }, [latexSource, wsPath]);

  const snapshot = latexSource.getSnapshot(wsPath);
  const parsed = React.useMemo(() => parseBibTeX(snapshot?.text ?? ''), [snapshot?.text]);

  const updateField = (entryKey: string, name: string, value: string) => {
    const current = latexSource.getSnapshot(wsPath);
    if (!current) return;
    const currentParsed = parseBibTeX(current.text);
    const entry = currentParsed.entries.find((candidate) => candidate.key === entryKey);
    if (!entry) {
      toast.error(t.app.bibliography.entryChanged);
      return;
    }
    const existing = getBibField(entry, name)?.value ?? '';
    if (existing === value) return;
    try {
      latexSource.applyEdit(wsPath, createBibFieldEdit(current.text, entry, name, value), 'visual');
    } catch (reason) {
      console.error('Unable to update bibliography field', reason);
      toast.error(t.app.bibliography.editFailed);
    }
  };

  if (loading) return <div className="flex min-h-48 items-center justify-center text-muted-foreground">{t.app.bibliography.loading}</div>;
  if (error || !snapshot) return <div className="p-6 text-sm text-destructive" role="alert">{t.app.bibliography.loadFailed}</div>;

  return (
    <section className="min-h-0 flex-1 overflow-auto p-5" data-editor-engine="bib-visual" data-ws-path={wsPath}>
      <div className="mx-auto max-w-4xl space-y-4">
        <div className="flex items-center gap-2">
          <div>
            <h2 className="font-semibold text-lg">{t.app.bibliography.references}</h2>
            <p className="text-muted-foreground text-sm">{t.app.bibliography.losslessNotice}</p>
          </div>
          <span className="ml-auto rounded bg-muted px-2 py-1 text-xs">{t.app.bibliography.entries({ count: parsed.entries.length })}</span>
        </div>
        {parsed.diagnostics.length > 0 && (
          <div className="rounded border border-amber-400/50 bg-amber-50 p-3 text-amber-900 text-sm dark:bg-amber-950/30 dark:text-amber-200">
            {parsed.diagnostics.map((item) => (
              <div key={`${item.kind}:${item.key ?? ''}:${item.offset ?? ''}:${item.message}`}>
                {item.message}
              </div>
            ))}
          </div>
        )}
        {parsed.entries.length === 0 ? (
          <p className="rounded border p-5 text-muted-foreground text-sm">{t.app.bibliography.empty}</p>
        ) : parsed.entries.map((entry) => (
          <article key={entry.id} className="rounded-lg border bg-card p-4 shadow-sm">
            <div className="mb-4 flex flex-wrap items-center gap-2">
              <strong className="font-mono text-sm">{entry.key}</strong>
              <span className="rounded bg-muted px-2 py-0.5 text-xs">@{entry.type}</span>
            </div>
            <div className="grid gap-3 md:grid-cols-2">
              {PRIMARY_FIELDS.map((fieldName) => {
                const field = getBibField(entry, fieldName);
                return (
                  <div key={fieldName} className={fieldName === 'title' || fieldName === 'author' ? 'md:col-span-2' : ''}>
                    <Label htmlFor={`${entry.id}-${fieldName}`}>{fieldName}</Label>
                    <Input
                      id={`${entry.id}-${fieldName}`}
                      defaultValue={field?.value ?? ''}
                      key={`${entry.id}-${fieldName}-${field?.value ?? ''}`}
                      placeholder={field ? undefined : t.app.bibliography.addField({ field: fieldName })}
                      onBlur={(event) => updateField(entry.key, fieldName, event.currentTarget.value)}
                    />
                  </div>
                );
              })}
            </div>
            {entry.fields.some((field) => !PRIMARY_FIELDS.includes(field.name as (typeof PRIMARY_FIELDS)[number])) && (
              <details className="mt-4">
                <summary className="cursor-pointer text-muted-foreground text-sm">{t.app.bibliography.otherFields}</summary>
                <div className="mt-3 grid gap-3 md:grid-cols-2">
                  {entry.fields.filter((field) => !PRIMARY_FIELDS.includes(field.name as (typeof PRIMARY_FIELDS)[number])).map((field) => (
                    <div key={`${entry.id}-${field.name}`}>
                      <Label htmlFor={`${entry.id}-${field.name}`}>{field.name}</Label>
                      <Input
                        id={`${entry.id}-${field.name}`}
                        defaultValue={field.value}
                        key={`${entry.id}-${field.name}-${field.value}`}
                        onBlur={(event) => updateField(entry.key, field.name, event.currentTarget.value)}
                      />
                    </div>
                  ))}
                </div>
              </details>
            )}
          </article>
        ))}
        <div className="flex justify-end">
          <Button variant="outline" onClick={() => void latexSource.flush(wsPath)}>{t.app.latexSourceEditor.save}</Button>
        </div>
      </div>
    </section>
  );
}
