import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

interface NotesPanelProps {
  filePath: string | null; // e.g. "cve/foo.md"
  onSaved?: () => void;
  onSelectFile?: (filePath: string) => void; // called after new note created
}

interface ParsedFm {
  title: string;
  visibility: 'private' | 'org' | 'public';
  scope_org_id: string;
  mode_hint: '' | 'search' | 'inject';
  tags: string;
  body: string;
}

function parseMdToFmAndBody(md: string): ParsedFm {
  // Lightweight FM parse (UI-side)
  const m = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(md);
  if (!m) {
    return { title: '', visibility: 'private', scope_org_id: '', mode_hint: '', tags: '', body: md };
  }
  const fmText = m[1]!;
  const body = m[2] ?? '';
  const get = (k: string): string => {
    const re = new RegExp(`^${k}:\\s*(.+)$`, 'm');
    const found = re.exec(fmText);
    return found ? found[1]!.trim().replace(/^['"]|['"]$/g, '') : '';
  };
  const tagsArr = /^tags:\s*\[([^\]]*)\]$/m.exec(fmText);
  return {
    title: get('title'),
    visibility: (get('visibility') as ParsedFm['visibility']) || 'private',
    scope_org_id: get('scope_org_id'),
    mode_hint: (get('mode_hint') as ParsedFm['mode_hint']) || '',
    tags: tagsArr ? tagsArr[1]!.split(',').map((s) => s.trim()).filter(Boolean).join(', ') : '',
    body,
  };
}

function serializeFm(p: ParsedFm): string {
  const fm: string[] = ['---'];
  if (p.title) fm.push(`title: ${p.title}`);
  fm.push(`visibility: ${p.visibility}`);
  if (p.visibility === 'org' && p.scope_org_id) fm.push(`scope_org_id: ${p.scope_org_id}`);
  if (p.mode_hint) fm.push(`mode_hint: ${p.mode_hint}`);
  const tagsArr = p.tags.split(',').map((s) => s.trim()).filter(Boolean);
  if (tagsArr.length > 0) fm.push(`tags: [${tagsArr.join(', ')}]`);
  fm.push('---');
  fm.push('');
  fm.push(p.body);
  return fm.join('\n');
}

const NAME_RE = /^[a-zA-Z0-9._-]+$/;

function NewNoteForm({ onCreated }: { onCreated: (filePath: string) => void }) {
  const { t } = useTranslation('userfolder');
  const qc = useQueryClient();
  const [folder, setFolder] = useState('');
  const [fileName, setFileName] = useState('');
  const [error, setError] = useState('');
  const [creating, setCreating] = useState(false);

  const handleCreate = async () => {
    const fn = fileName.endsWith('.md') ? fileName : `${fileName}.md`;
    if (!NAME_RE.test(folder)) { setError(t('notes.newNoteForm.errorFolder')); return; }
    if (!NAME_RE.test(fn)) { setError(t('notes.newNoteForm.errorFile')); return; }
    setError('');
    setCreating(true);
    try {
      const stub = `---\nvisibility: private\n---\n\n`;
      const r = await fetch(
        `/api/users/me/folder/file?subdir=notes&path=${encodeURIComponent(`${folder}/${fn}`)}`,
        {
          method: 'PUT',
          credentials: 'include',
          headers: { 'Content-Type': 'text/plain; charset=utf-8' },
          body: stub,
        },
      );
      if (!r.ok) {
        const j = await r.json().catch(() => ({ error: 'save failed' }));
        throw new Error((j as { error?: string }).error ?? 'save failed');
      }
      qc.invalidateQueries({ queryKey: ['userfolder', 'list', 'notes'] });
      onCreated(`${folder}/${fn}`);
    } catch (err) {
      setError((err as Error).message);
    } finally {
      setCreating(false);
    }
  };

  return (
    <div className="mt-6 border border-hairline rounded-md p-4 bg-surface-2/40">
      <p className="text-[13px] font-semibold text-slate-700 mb-3">{t('notes.newNoteForm.title')}</p>
      <div className="flex flex-col gap-2">
        <div className="flex gap-2 items-center">
          <input
            className="flex-1 border border-hairline rounded px-2 py-1 text-[13px] bg-canvas focus:outline-none focus:ring-1 focus:ring-accent"
            placeholder={t('notes.newNoteForm.folderPlaceholder')}
            value={folder}
            onChange={(e) => setFolder(e.target.value)}
          />
          <span className="text-slate-400 text-[13px]">/</span>
          <input
            className="flex-1 border border-hairline rounded px-2 py-1 text-[13px] bg-canvas focus:outline-none focus:ring-1 focus:ring-accent"
            placeholder={t('notes.newNoteForm.filePlaceholder')}
            value={fileName}
            onChange={(e) => setFileName(e.target.value)}
          />
        </div>
        {error && <p className="text-2xs text-red-600">{error}</p>}
        <button
          type="button"
          className="self-start px-3 py-1 rounded-md text-2xs font-semibold bg-accent text-accent-fg hover:bg-accent-deep transition-colors disabled:opacity-50"
          disabled={creating || !folder || !fileName}
          onClick={handleCreate}
        >
          {creating ? t('notes.newNoteForm.creating') : t('notes.newNoteForm.create')}
        </button>
      </div>
    </div>
  );
}

export function NotesPanel({ filePath, onSaved, onSelectFile }: NotesPanelProps) {
  const { t } = useTranslation('userfolder');
  const qc = useQueryClient();

  const { data: fileText, isLoading, isError } = useQuery({
    queryKey: ['notes-file', filePath],
    queryFn: async () => {
      if (!filePath) return '';
      const r = await fetch(
        `/api/users/me/folder/file?subdir=notes&path=${encodeURIComponent(filePath)}`,
        { credentials: 'include' },
      );
      if (!r.ok) throw new Error(`${r.status}`);
      return r.text();
    },
    enabled: !!filePath,
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  });

  const [state, setState] = useState<ParsedFm>({
    title: '',
    visibility: 'private',
    scope_org_id: '',
    mode_hint: '',
    tags: '',
    body: '',
  });

  useEffect(() => {
    if (fileText !== undefined) setState(parseMdToFmAndBody(fileText));
  }, [fileText]);

  const save = useMutation({
    mutationFn: async () => {
      if (!filePath) return;
      const md = serializeFm(state);
      const r = await fetch(
        `/api/users/me/folder/file?subdir=notes&path=${encodeURIComponent(filePath)}`,
        {
          method: 'PUT',
          credentials: 'include',
          headers: { 'Content-Type': 'text/plain; charset=utf-8' },
          body: md,
        },
      );
      if (!r.ok) {
        const j = await r.json().catch(() => ({ error: 'save failed' }));
        throw new Error((j as { error?: string }).error ?? 'save failed');
      }
    },
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['notes-file', filePath] });
      qc.invalidateQueries({ queryKey: ['userfolder', 'list', 'notes'] });
      onSaved?.();
    },
  });

  if (!filePath) {
    return (
      <div className="h-full overflow-y-auto">
        <div className="max-w-2xl mx-auto px-6 py-8">
          <div className="mb-6 flex gap-3">
            <span className="text-2xl leading-none mt-0.5 select-none" aria-hidden>📝</span>
            <div className="flex-1 min-w-0">
              <h2 className="text-base font-semibold text-slate-900">{t('notes.introTitle')}</h2>
              <p className="text-[13px] text-slate-500 mt-1 leading-relaxed">
                {t('notes.introBody')}
              </p>
            </div>
          </div>
          <div className="bg-surface-2 rounded-md p-4 text-[13px] font-mono text-slate-600 whitespace-pre leading-relaxed">
            {t('notes.formatExample')}
          </div>
          <div className="mt-6 text-[13px] text-slate-500 space-y-2">
            <p>
              <span className="font-semibold text-slate-700">{t('notes.shareLabel')}</span>{' '}
              {t('notes.shareBody')}
            </p>
            <p>
              <span className="font-semibold text-slate-700">{t('notes.agentLabel')}</span>{' '}
              {t('notes.agentBody')}
            </p>
          </div>
          <NewNoteForm onCreated={(path) => {
            onSaved?.();
            onSelectFile?.(path);
          }} />
        </div>
      </div>
    );
  }

  if (isLoading) {
    return (
      <div className="h-full flex items-center justify-center text-[13px] text-slate-400">
        Loading…
      </div>
    );
  }

  if (isError) {
    return (
      <div className="h-full flex items-center justify-center text-[13px] text-red-500">
        {t('notes.loadFailed')}
      </div>
    );
  }

  return (
    <div className="h-full flex flex-col overflow-hidden">
      {/* Header */}
      <div className="flex-shrink-0 px-4 py-3 border-b border-hairline bg-surface-2/30">
        <div className="flex items-center justify-between">
          <div>
            <h2 className="text-[13px] font-semibold text-slate-900 font-mono">{filePath}</h2>
            <p className="text-2xs text-slate-500 mt-0.5">
              {t('notes.fmHint')}
            </p>
          </div>
          <button
            type="button"
            className="px-3 py-1 rounded-md text-2xs font-semibold bg-accent text-accent-fg hover:bg-accent-deep transition-colors disabled:opacity-50"
            disabled={save.isPending}
            onClick={() => save.mutate()}
          >
            {save.isPending ? 'Saving…' : 'Save'}
          </button>
        </div>
        {save.isError && (
          <p className="mt-1 text-2xs text-red-600">{(save.error as Error).message}</p>
        )}
      </div>

      {/* FM form */}
      <div className="flex-shrink-0 px-4 py-3 border-b border-hairline bg-surface-2/20">
        <div className="grid grid-cols-2 gap-x-4 gap-y-2">
          {/* Title */}
          <label className="flex flex-col gap-0.5">
            <span className="text-2xs font-medium text-slate-500 uppercase tracking-wide">Title</span>
            <input
              className="border border-hairline rounded px-2 py-1 text-[13px] bg-canvas focus:outline-none focus:ring-1 focus:ring-accent"
              value={state.title}
              onChange={(e) => setState({ ...state, title: e.target.value })}
              placeholder="(optional)"
            />
          </label>

          {/* Visibility */}
          <label className="flex flex-col gap-0.5">
            <span className="text-2xs font-medium text-slate-500 uppercase tracking-wide">Visibility</span>
            <select
              className="border border-hairline rounded px-2 py-1 text-[13px] bg-canvas focus:outline-none focus:ring-1 focus:ring-accent"
              value={state.visibility}
              onChange={(e) => setState({ ...state, visibility: e.target.value as ParsedFm['visibility'] })}
            >
              <option value="private">private</option>
              <option value="org">org</option>
              <option value="public">public</option>
            </select>
          </label>

          {/* Scope org id — conditional */}
          {state.visibility === 'org' && (
            <label className="flex flex-col gap-0.5">
              <span className="text-2xs font-medium text-slate-500 uppercase tracking-wide">Scope Org ID</span>
              <input
                className="border border-hairline rounded px-2 py-1 text-[13px] bg-canvas focus:outline-none focus:ring-1 focus:ring-accent"
                value={state.scope_org_id}
                onChange={(e) => setState({ ...state, scope_org_id: e.target.value })}
                placeholder="gitea-org-name"
              />
            </label>
          )}

          {/* Mode hint */}
          <label className="flex flex-col gap-0.5">
            <span className="text-2xs font-medium text-slate-500 uppercase tracking-wide">Mode Hint</span>
            <select
              className="border border-hairline rounded px-2 py-1 text-[13px] bg-canvas focus:outline-none focus:ring-1 focus:ring-accent"
              value={state.mode_hint}
              onChange={(e) => setState({ ...state, mode_hint: e.target.value as ParsedFm['mode_hint'] })}
            >
              <option value="">(none)</option>
              <option value="search">search</option>
              <option value="inject">inject</option>
            </select>
          </label>

          {/* Tags */}
          <label className="flex flex-col gap-0.5 col-span-2">
            <span className="text-2xs font-medium text-slate-500 uppercase tracking-wide">{t('notes.tags')}</span>
            <input
              className="border border-hairline rounded px-2 py-1 text-[13px] bg-canvas focus:outline-none focus:ring-1 focus:ring-accent"
              value={state.tags}
              onChange={(e) => setState({ ...state, tags: e.target.value })}
              placeholder="security, cve, ..."
            />
          </label>
        </div>
      </div>

      {/* Markdown body */}
      <div className="flex-1 min-h-0 overflow-hidden">
        <textarea
          className="w-full h-full resize-none p-4 font-mono text-[13px] text-slate-800 bg-canvas focus:outline-none"
          value={state.body}
          onChange={(e) => setState({ ...state, body: e.target.value })}
          placeholder="Markdown body…"
          spellCheck={false}
        />
      </div>
    </div>
  );
}
