// views.jsx — all top-level views: Login, Dashboard, Upload, Processing, Results.
// Each is a plain React function component that takes app state + actions.

// ── Shared icons ─────────────────────────────────────────────────────────
const Icon = {
  upload: (
    <svg width="20" height="20" viewBox="0 0 20 20" fill="none">
      <path d="M10 13V3M10 3l-4 4M10 3l4 4M3 14v2a2 2 0 002 2h10a2 2 0 002-2v-2"
            stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  ),
  doc: (
    <svg width="18" height="18" viewBox="0 0 18 18" fill="none">
      <path d="M11 1.5H4.5A1.5 1.5 0 003 3v12A1.5 1.5 0 004.5 16.5h9A1.5 1.5 0 0015 15V5.5L11 1.5z"
            stroke="currentColor" strokeWidth="1.25" strokeLinejoin="round"/>
      <path d="M11 1.5V5.5H15" stroke="currentColor" strokeWidth="1.25" strokeLinejoin="round"/>
    </svg>
  ),
  x: <svg width="14" height="14" viewBox="0 0 14 14"><path d="M3 3l8 8M11 3l-8 8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>,
  download: (
    <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
      <path d="M7 1v8M4 6l3 3 3-3M2 12h10" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  ),
  check: <svg width="12" height="12" viewBox="0 0 12 12"><path d="M2 6l3 3 5-6" stroke="currentColor" strokeWidth="1.75" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  arrow: <svg width="12" height="12" viewBox="0 0 12 12"><path d="M3 6h6M6 3l3 3-3 3" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>,
};

// ── Login ─────────────────────────────────────────────────────────────────
function LoginView({ onLogin }) {
  const [user, setUser] = React.useState('');
  const [pw, setPw] = React.useState('');
  const [err, setErr] = React.useState('');
  const [loading, setLoading] = React.useState(false);

  const submit = async (e) => {
    e.preventDefault();
    setErr(''); setLoading(true);
    try {
      await onLogin(user.trim().toLowerCase(), pw);
    } catch (e) {
      setErr(e.message || 'Sign-in failed');
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="login-wrap">
      <form className="login-card" onSubmit={submit}>
        <div className="brand">
          <div className="brand-mark">APE</div>
          <span>Automatic Post-Editing</span>
        </div>
        <div className="tagline">MQM assessment &amp; post-edit</div>

        <div className="field">
          <label htmlFor="u">Username</label>
          <input id="u" type="text" autoFocus autoComplete="username"
                 value={user} onChange={(e) => setUser(e.target.value)} />
        </div>
        <div className="field">
          <label htmlFor="p">Password</label>
          <input id="p" type="password" autoComplete="current-password"
                 value={pw} onChange={(e) => setPw(e.target.value)} />
        </div>

        <button className="btn block lg" type="submit" disabled={loading || !user || !pw}>
          {loading ? <><span className="spinner" /> &nbsp;Signing in</> : 'Sign in'}
        </button>
        {err && <div className="login-error">{err}</div>}
      </form>
    </div>
  );
}

// ── Topbar ────────────────────────────────────────────────────────────────
function Topbar({ user, view, onNav, onLogout }) {
  return (
    <div className="topbar">
      <div className="brand" style={{ cursor: 'pointer' }} onClick={() => onNav('dashboard')}>
        <div className="brand-mark">APE</div>
        <span>Automatic Post-Editing</span>
      </div>
      <div className="topbar-meta">
        {view !== 'dashboard' && view !== 'login' && (
          <button className="logout" onClick={() => onNav('dashboard')}>{'\u2190'} Projects</button>
        )}
        <span className="user">{user}</span>
        <button className="logout" onClick={onLogout}>Sign out</button>
      </div>
    </div>
  );
}

// ── Dashboard / Project history ───────────────────────────────────────────
function DashboardView({ history, onNewProject, onOpenProject, onDeleteProject }) {
  return (
    <>
      <div className="page-h">
        <div>
          <h1 className="page-title">Projects</h1>
          <div className="page-sub">{history.length} assessment{history.length === 1 ? '' : 's'} on record</div>
        </div>
        <div className="page-actions">
          <button className="btn lg" onClick={onNewProject}>{Icon.upload}&nbsp;&nbsp;New assessment</button>
        </div>
      </div>

      {history.length === 0 ? (
        <div className="empty">
          No projects yet. Click <b>New assessment</b> to upload a source + translation.
        </div>
      ) : (
        <table className="history-table">
          <thead>
            <tr>
              <th>Name</th>
              <th>Pair</th>
              <th>Words</th>
              <th>Errors</th>
              <th className="qs-col">Quality</th>
              <th>Created</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {history.map((p) => (
              <tr key={p.id} className="clickable" onClick={() => onOpenProject(p.id)}>
                <td><b>{p.name}</b></td>
                <td className="num">{p.data.source_language_code || '?'} {'\u2192'} {p.data.target_language_code || '?'}</td>
                <td className="num">{(p.data.metrics?.source_word_count || 0).toLocaleString()}</td>
                <td className="num">{(p.data.errors || []).length}</td>
                <td className="num qs-col">{(p.data.metrics?.quality_score || 0).toFixed(2)}%</td>
                <td className="num">{new Date(p.createdAt).toLocaleString()}</td>
                <td>
                  <button className="btn sm secondary" onClick={(e) => { e.stopPropagation(); onDeleteProject(p.id); }}>Delete</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      )}

      <div className="api-card">
        <h4>API endpoint (for CI/CD)</h4>
        <pre>{`curl -X POST https://ape.yaroslavmar.com/api/v1/assess \\
  -u yaroslav:\u2022\u2022\u2022\u2022\u2022\u2022\u2022 \\
  -F "source=@source.docx" \\
  -F "target=@translation.docx" \\
  -F "glossary=@glossary.txt" \\
  -o report.zip   # contains MQM.xlsx + corrected.docx`}</pre>
      </div>
    </>
  );
}

// ── Upload ────────────────────────────────────────────────────────────────
function FileDrop({ label, file, onFile, onClear, accept }) {
  const [hover, setHover] = React.useState(false);
  const [preview, setPreview] = React.useState('');
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    if (!file) { setPreview(''); return; }
    const ext = file.name.toLowerCase().split('.').pop();
    if (ext === 'pdf') {
      setPreview('PDF document \u2014 text extracted when assessment runs.');
      return;
    }
    (async () => {
      try {
        const parsed = await window.parseFile(file);
        setPreview(parsed.text.slice(0, 600));
      } catch (e) {
        setPreview('\u26a0 ' + e.message);
      }
    })();
  }, [file]);

  const handleFiles = (files) => {
    if (files && files[0]) onFile(files[0]);
  };

  if (file) {
    return (
      <div className="dropzone filled">
        <div className="dropzone-label">{label}</div>
        <button className="clear" onClick={onClear} title="Remove">{Icon.x}</button>
        <div className="file-card">
          <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
            <div style={{ color: 'var(--ink-3)', flexShrink: 0 }}>{Icon.doc}</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div className="filename">{file.name}</div>
              <div className="meta">
                <span>{window.formatSize(file.size)}</span>
                <span>{file.type || file.name.split('.').pop().toUpperCase()}</span>
              </div>
            </div>
          </div>
          {preview && <div className="preview">{preview}</div>}
        </div>
      </div>
    );
  }

  return (
    <div
      className={'dropzone' + (hover ? ' hover' : '')}
      onClick={() => inputRef.current.click()}
      onDragOver={(e) => { e.preventDefault(); setHover(true); }}
      onDragLeave={() => setHover(false)}
      onDrop={(e) => { e.preventDefault(); setHover(false); handleFiles(e.dataTransfer.files); }}
    >
      <div className="dropzone-label">{label}</div>
      <div className="dropzone-icon">{Icon.upload}</div>
      <div style={{ fontWeight: 500 }}>Click or drop a file</div>
      <div className="dropzone-hint">.docx · .txt · .xlsx · .tmx · .xlf · .xliff · .pdf*</div>
      <input ref={inputRef} type="file" accept={accept} hidden
             onChange={(e) => handleFiles(e.target.files)} />
    </div>
  );
}

function UploadView({ onRun }) {
  const [source, setSource] = React.useState(null);
  const [target, setTarget] = React.useState(null);
  const [glossary, setGlossary] = React.useState('');
  const [projectName, setProjectName] = React.useState('');
  const [sourceLang, setSourceLang] = React.useState('auto');
  const [targetLang, setTargetLang] = React.useState('auto');
  const [busy, setBusy] = React.useState(false);

  const canRun = source && target && !busy;
  const accept = '.txt,.docx,.xlsx,.tmx,.xlf,.xliff,.pdf,.md';

  const handleRun = async () => {
    setBusy(true);
    try {
      const srcParsed = await window.parseFile(source);
      const tgtParsed = await window.parseFile(target);

      // Bilingual file (xlsx/tmx/xlf) — derive both source and target from one upload.
      let sourceText = srcParsed.text;
      let targetText = tgtParsed.text;
      if (srcParsed.kind === 'bilingual' && srcParsed.extra) {
        sourceText = srcParsed.extra.source;
        // If both files are bilingual and the second is the same kind, prefer the target half
        if (tgtParsed.kind === 'bilingual') {
          targetText = tgtParsed.extra.target;
        }
      }

      const name = projectName.trim() || source.name.replace(/\.[^.]+$/, '');
      onRun({
        name,
        sourceFile: source.name,
        targetFile: target.name,
        sourceText,
        targetText,
        glossary,
        sourceLang,
        targetLang,
      });
    } catch (e) {
      alert('Failed to parse files: ' + e.message);
    } finally {
      setBusy(false);
    }
  };

  return (
    <>
      <div className="page-h">
        <div>
          <h1 className="page-title">New assessment</h1>
          <div className="page-sub">Upload the source and its translation. Languages auto-detected.</div>
        </div>
      </div>

      <div className="upload-grid">
        <FileDrop label="Source" file={source} onFile={setSource} onClear={() => setSource(null)} accept={accept} />
        <FileDrop label="Translation" file={target} onFile={setTarget} onClear={() => setTarget(null)} accept={accept} />
      </div>

      <details className="advanced">
        <summary>Advanced — glossary, language hints, project name</summary>
        <div className="advanced-body">
          <div className="field">
            <label htmlFor="pn">Project name</label>
            <input id="pn" type="text" placeholder="(derived from filename)"
                   value={projectName} onChange={(e) => setProjectName(e.target.value)} />
          </div>
          <div className="field">
            <label htmlFor="gl">Glossary / TM (one term per line, format: <code>source = target</code>)</label>
            <textarea id="gl" rows={4} className="" style={{
              background: 'var(--bg)', border: '1px solid var(--line)',
              borderRadius: 'var(--rad)', padding: '8px 10px',
              fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--ink)',
              resize: 'vertical',
            }} placeholder={'\u043d\u0435\u0439\u0440\u043e\u043d\u043d\u0430\u044f \u0441\u0435\u0442\u044c = neural network\n\u0441\u0442\u043e\u0445\u0430\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 = stochastic'}
                      value={glossary} onChange={(e) => setGlossary(e.target.value)} />
          </div>
          <div className="field">
            <label htmlFor="sl">Source language (optional)</label>
            <input id="sl" placeholder="auto-detect (e.g. ru, en, es, zh, ja)"
                   value={sourceLang === 'auto' ? '' : sourceLang}
                   onChange={(e) => setSourceLang(e.target.value || 'auto')} />
          </div>
          <div className="field">
            <label htmlFor="tl">Target language (optional)</label>
            <input id="tl" placeholder="auto-detect"
                   value={targetLang === 'auto' ? '' : targetLang}
                   onChange={(e) => setTargetLang(e.target.value || 'auto')} />
          </div>
        </div>
      </details>

      <div className="run-row">
        <div className="summary">
          <span>Source: <b>{source ? source.name : '\u2014'}</b></span>
          <span>Target: <b>{target ? target.name : '\u2014'}</b></span>
          <span>Model: <b>claude-opus-4-7</b></span>
        </div>
        <button className="btn lg accent" disabled={!canRun} onClick={handleRun}>
          {busy ? <><span className="spinner" /> &nbsp;Preparing</> : <>Run MQM assessment&nbsp;&nbsp;{Icon.arrow}</>}
        </button>
      </div>
    </>
  );
}

// ── Processing ────────────────────────────────────────────────────────────
function ProcessingView({ project, onDone, onError }) {
  const [steps, setSteps] = React.useState([
    { id: 'parse', name: 'Parse documents', detail: '', state: 'active' },
    { id: 'detect', name: 'Detect languages and segment', detail: '', state: 'pending' },
    { id: 'assess', name: 'Run MQM assessment (Claude Opus)', detail: '', state: 'pending' },
    { id: 'metrics', name: 'Score, compute edit distance', detail: '', state: 'pending' },
    { id: 'render', name: 'Generate report and corrected DOCX', detail: '', state: 'pending' },
  ]);
  const [log, setLog] = React.useState([]);

  // Lock processing to one run per project mount — React StrictMode and
  // re-renders should not cause a second Claude call.
  const startedRef = React.useRef(false);

  const pushLog = (msg) => {
    const t = new Date().toTimeString().slice(0, 8);
    setLog((L) => [...L, { t, msg }].slice(-200));
  };

  const setStep = (id, state, detail) => {
    setSteps((S) => S.map((s) => s.id === id ? { ...s, state, detail: detail ?? s.detail } : s));
  };

  React.useEffect(() => {
    if (startedRef.current) return;
    startedRef.current = true;

    (async () => {
      try {
        pushLog(`Loaded source (${window.formatSize(new Blob([project.sourceText]).size)})`);
        pushLog(`Loaded target (${window.formatSize(new Blob([project.targetText]).size)})`);
        setStep('parse', 'done', 'parsed source + target');

        setStep('detect', 'active');
        pushLog('Handing off to Claude for language detection + sentence segmentation');
        await new Promise((r) => setTimeout(r, 400));
        setStep('detect', 'done', 'pipelined with assessment call');

        setStep('assess', 'active');
        const data = await window.runMqmAssessment({
          sourceText: project.sourceText,
          targetText: project.targetText,
          glossary: project.glossary,
          onLog: pushLog,
        });
        setStep('assess', 'done',
          `${(data.segments || []).length} segments, ${(data.errors || []).length} errors flagged`);

        setStep('metrics', 'active');
        await new Promise((r) => setTimeout(r, 200));
        pushLog(`Quality Score: ${data.metrics.quality_score.toFixed(2)}%`);
        pushLog(`Penalty: ${data.metrics.penalty} pts over ${data.metrics.source_word_count} words`);
        setStep('metrics', 'done', `score ${data.metrics.quality_score.toFixed(2)}%`);

        setStep('render', 'active');
        await new Promise((r) => setTimeout(r, 300));
        pushLog('XLSX (4 sheets) + DOCX (clean post-edit) ready');
        setStep('render', 'done', 'reports ready');

        onDone(data);
      } catch (e) {
        pushLog('ERROR: ' + (e.message || String(e)));
        onError(e);
      }
    })();
    // eslint-disable-next-line
  }, []);

  return (
    <div className="proc-wrap">
      <div className="proc-card">
        <h2 className="proc-title">Running assessment</h2>
        <div className="proc-sub">{project.name} &nbsp;·&nbsp; claude-opus-4-7</div>

        <div className="proc-steps">
          {steps.map((s) => (
            <div key={s.id} className={'proc-step ' + s.state}>
              <div className="dot" />
              <div className="step-body">
                <div className="step-name">{s.name}</div>
                {s.detail && <div className="step-detail">{s.detail}</div>}
              </div>
            </div>
          ))}
        </div>

        <div className="proc-log">
          {log.map((l, i) => (
            <div key={i}><span className="log-time">{l.t}</span>{l.msg}</div>
          ))}
          {log.length === 0 && <div style={{ color: 'var(--ink-4)' }}>Awaiting first message…</div>}
        </div>
      </div>
    </div>
  );
}

// Object.assign exports continue in views-results.jsx (Results)
Object.assign(window, {
  Icon, LoginView, Topbar, DashboardView, UploadView, ProcessingView, FileDrop,
});
