import React, { useEffect, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { api } from '../api';
import { Button, Badge, Notice, LengthMeter } from './ui';
import { IconSparkle } from './icons';

/**
 * The review card: what the AI proposes for this page, next to what is there.
 *
 * Nothing on this card writes to the page except the Apply button, and Apply
 * writes what is in the two editable fields — the proposal as it came, or as
 * the person changed it. Everything a reviewer needs to decide is on the
 * card: the original, the proposal, why, how confident, what to double-check,
 * which model, what it cost. Undo puts back the exact previous values.
 *
 * A proposal made from unchanged content is served from storage; the button
 * says so, so nobody wonders why the second press was free.
 */

/** Word-level diff, enough to see what moved. */
function Diff({ from, to }) {
	const a = String(from || '').split(/\s+/).filter(Boolean);
	const b = String(to || '').split(/\s+/).filter(Boolean);
	// LCS on words; both strings are short.
	const m = a.length;
	const n = b.length;
	const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
	for (let i = m - 1; i >= 0; i--) for (let j = n - 1; j >= 0; j--) dp[i][j] = a[i] === b[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
	const out = [];
	let i = 0;
	let j = 0;
	while (i < m && j < n) {
		if (a[i] === b[j]) {
			out.push(['=', a[i]]);
			i++;
			j++;
		} else if (dp[i + 1][j] >= dp[i][j + 1]) {
			out.push(['-', a[i]]);
			i++;
		} else {
			out.push(['+', b[j]]);
			j++;
		}
	}
	while (i < m) out.push(['-', a[i++]]);
	while (j < n) out.push(['+', b[j++]]);
	if (a.length === 0) return <span className="ars-diff-add">{b.join(' ')}</span>;
	return (
		<span>
			{out.map(([k, w], idx) => (
				<span key={idx} className={k === '+' ? 'ars-diff-add' : k === '-' ? 'ars-diff-del' : ''}>
					{w}{' '}
				</span>
			))}
		</span>
	);
}

export default function AiReview({ postId, onApplied }) {
	const [state, setState] = useState(null);
	const [title, setTitle] = useState('');
	const [desc, setDesc] = useState('');
	const [busy, setBusy] = useState('');
	const [error, setError] = useState(null);
	const [showHistory, setShowHistory] = useState(false);

	const load = () =>
		api
			.get(`/ai/suggest/${postId}`)
			.then((s) => {
				setState(s);
				if (s.pending) {
					setTitle(s.pending.proposal.title || '');
					setDesc(s.pending.proposal.description || '');
				}
			})
			.catch((e) => setError(e.message));

	useEffect(() => {
		load();
	}, [postId]); // eslint-disable-line react-hooks/exhaustive-deps

	const run = async (name, fn) => {
		setBusy(name);
		setError(null);
		try {
			await fn();
		} catch (e) {
			setError(e.message);
		} finally {
			setBusy('');
		}
	};

	const propose = (force = false) =>
		run('propose', async () => {
			const s = await api.post(`/ai/suggest/${postId}`, { force });
			setState({ pending: s, stale: false, history: s.history || [], current: s.current });
			setTitle(s.proposal.title || '');
			setDesc(s.proposal.description || '');
		});

	const apply = () =>
		run('apply', async () => {
			const r = await api.post(`/ai/suggest/${postId}/apply`, { title, description: desc });
			setState((prev) => ({ ...(prev || {}), current: { title: r.title || '', description: r.description || '' } }));
			setState((prev) => ({ pending: null, stale: false, history: r.history || [], current: r.current || prev?.current }));
			if (onApplied) onApplied({ seo_title: r.title, seo_desc: r.description });
		});

	const reject = () =>
		run('reject', async () => {
			const r = await api.post(`/ai/suggest/${postId}/reject`, {});
			setState((prev) => ({ pending: null, stale: false, history: r.history || [], current: r.current || prev?.current }));
		});

	const undo = () =>
		run('undo', async () => {
			const r = await api.post(`/ai/suggest/${postId}/undo`, {});
			setState((s) => ({ ...s, history: r.history || [] }));
			if (onApplied) onApplied({ seo_title: r.restored.title || '', seo_desc: r.restored.description || '' });
		});

	if (!state) return null;

	const p = state.pending;
	const canUndo = (state.history || []).some((h) => h.action === 'applied' && !h.undone);
	const edited = p && (title !== p.proposal.title || desc !== p.proposal.description);

	/*
	 * A proposal stored by an older version has no `original` block.
	 *
	 * Reading original.title threw, and because it threw during render the
	 * error boundary replaced the whole screen — a page with a stale proposal
	 * on it became unopenable, and nothing in the message said which page or
	 * why. Defaulting is enough: the before/after comparison degrades to
	 * showing the fallback, which is exactly what an empty SEO title means.
	 */
	/*
	 * "Now" is what the page carries at this moment, read fresh with every
	 * load, not the snapshot the proposal took when it was written. The
	 * snapshot belongs to the undo. A proposal made before an earlier apply
	 * showed that earlier title as "Now" while the list, reading the page,
	 * showed the real one, and the two screens disagreed about a fact.
	 */
	const snapshot = p?.original ?? { title: '', description: '', fallback_title: '' };
	const original = state?.current ? { ...snapshot, title: state.current.title || '', description: state.current.description || '' } : snapshot;
	const movedSince = !!(state?.current && p?.original && (state.current.title !== (p.original.title || '') || state.current.description !== (p.original.description || '')));

	/*
	 * The receipt block, likewise.
	 *
	 * A proposal written before the model receipt was recorded — or by a
	 * provider that reported none — has no `model`, and reading through it
	 * threw during render, which the error boundary turns into a blank screen
	 * for the whole page rather than a missing line in one panel.
	 */
	const model = p?.model ?? {};
	const conf = p ? p.proposal.confidence : 0;
	const confTone = conf >= 75 ? 'good' : conf >= 50 ? 'warning' : 'serious';

	return (
		<div className="ars-review">
			<div className="ars-review-head">
				<div className="flex items-center gap-2 flex-wrap">
					<IconSparkle size={14} />
					<span className="font-semibold text-[13px]">{__('AI proposal', 'ai-rank-suite')}</span>
					{p && (
						<>
							<Badge tone={confTone}>
								{conf}% {__('confident', 'ai-rank-suite')}
							</Badge>
							{p.cached && <Badge tone="neutral">{__('unchanged page — no new call', 'ai-rank-suite')}</Badge>}
							{state.stale && <Badge tone="warning">{__('page changed since', 'ai-rank-suite')}</Badge>}
							{movedSince && <Badge tone="warning" title={__('The title or description was changed after this proposal was written; the proposal compares against what the page carries now.', 'ai-rank-suite')}>{__('metadata changed since', 'ai-rank-suite')}</Badge>}
						</>
					)}
				</div>
				<div className="flex items-center gap-2 flex-wrap">
					{canUndo && (
						<Button variant="ghost" busy={busy === 'undo'} onClick={undo}>
							{__('Undo last apply', 'ai-rank-suite')}
						</Button>
					)}
					<Button variant={p ? 'ghost' : 'primary'} busy={busy === 'propose'} onClick={() => propose(!!p)}>
						{p ? __('Propose again', 'ai-rank-suite') : __('Propose title & description', 'ai-rank-suite')}
					</Button>
				</div>
			</div>

			{error && <Notice tone="serious">{error}</Notice>}

			{p && (
				<div className="grid gap-3">
					<div className="ars-review-field">
						<div className="t-overline">{__('SEO title', 'ai-rank-suite')}</div>
						<div className="ars-review-orig">
							<span className="t-caption">{__('Now', 'ai-rank-suite')}:</span>{' '}
							{original.title || <em style={{ color: 'var(--ars-ink-3)' }}>{__('empty — falls back to', 'ai-rank-suite')} “{original.fallback_title}”</em>}
						</div>
						<div className="ars-review-diff">
							<span className="t-caption">{__('Change', 'ai-rank-suite')}:</span> <Diff from={original.title || original.fallback_title} to={title} />
						</div>
						<input type="text" value={title} onChange={(e) => setTitle(e.target.value)} />
						<LengthMeter value={title} kind="title" />
						{p.proposal.title_reason && <div className="t-caption">{p.proposal.title_reason}</div>}
					</div>

					<div className="ars-review-field">
						<div className="t-overline">{__('Meta description', 'ai-rank-suite')}</div>
						<div className="ars-review-orig">
							<span className="t-caption">{__('Now', 'ai-rank-suite')}:</span>{' '}
							{original.description || <em style={{ color: 'var(--ars-ink-3)' }}>{__('empty', 'ai-rank-suite')}</em>}
						</div>
						<div className="ars-review-diff">
							<span className="t-caption">{__('Change', 'ai-rank-suite')}:</span> <Diff from={original.description} to={desc} />
						</div>
						<textarea rows={3} value={desc} onChange={(e) => setDesc(e.target.value)} />
						<LengthMeter value={desc} kind="description" />
						{p.proposal.description_reason && <div className="t-caption">{p.proposal.description_reason}</div>}
					</div>

					{(p.proposal.risks || []).length > 0 && (
						<Notice tone="warning">
							<strong>{__('Check before applying:', 'ai-rank-suite')}</strong> {(p.proposal.risks || []).join(' · ')}
						</Notice>
					)}

					<div className="ars-review-meta">
						{(model.provider || model.model) && (
							<span>
								{[model.provider, model.model].filter(Boolean).join(' · ')}
							</span>
						)}
						{model.prompt && <span>{model.prompt}</span>}
						{typeof model.tokens === 'number' && (
							<span>
								{model.tokens.toLocaleString()} {__('tokens', 'ai-rank-suite')}
								{model.cost ? ` · ${model.cost}` : ''}
								{model.latency_ms ? ` · ${model.latency_ms} ms` : ''}
							</span>
						)}
						<span>
							{__('language', 'ai-rank-suite')} {p.proposal.language}
							{p.proposal.chars_sent ? ` · ${p.proposal.chars_sent.toLocaleString()} ${__('chars sent', 'ai-rank-suite')}` : ''}
							{p.proposal.redacted && Object.keys(p.proposal.redacted).length > 0
								? ` · ${__('redacted', 'ai-rank-suite')}: ${Object.entries(p.proposal.redacted).map(([k, v]) => `${v} ${k}`).join(', ')}`
								: ''}
						</span>
					</div>

					<div className="flex items-center gap-2 flex-wrap">
						<Button busy={busy === 'apply'} onClick={apply}>
							{edited ? __('Apply my edited version', 'ai-rank-suite') : __('Apply proposal', 'ai-rank-suite')}
						</Button>
						<Button variant="ghost" busy={busy === 'reject'} onClick={reject}>
							{__('Reject', 'ai-rank-suite')}
						</Button>
					</div>
				</div>
			)}

			{(state.history || []).length > 0 && (
				<div className="mt-1">
					<button type="button" className="ars-linkbtn" onClick={() => setShowHistory((v) => !v)}>
						{showHistory ? __('Hide history', 'ai-rank-suite') : `${__('History', 'ai-rank-suite')} (${state.history.length})`}
					</button>
					{showHistory && (
						<div className="grid gap-1 mt-2">
							{[...state.history].reverse().map((h, i) => (
								<div key={i} className="text-[12px]" style={{ color: 'var(--ars-ink-2)' }}>
									{new Date(h.time * 1000).toLocaleString()} · <strong>{h.action}</strong>
									{h.edited ? ` (${__('edited', 'ai-rank-suite')})` : ''}
									{h.undone ? ` · ${__('undone', 'ai-rank-suite')}` : ''}
									{h.model?.model ? ` · ${h.model.model}` : ''}
									{h.model?.cost ? ` · ${h.model.cost}` : ''}
									{h.after?.title ? ` — “${h.after.title}”` : ''}
								</div>
							))}
						</div>
					)}
				</div>
			)}
		</div>
	);
}
