import { __, _n, sprintf } from '@wordpress/i18n';
import React, { useEffect, useState } from 'react';
import { api } from '../api';
import { Card, Button, Switch, Badge, Tabs, Notice, Advisor, Panel, MetricGrid, PageState, Progress } from '../components/ui';
import { IconExternal, IconX, IconSpark } from '../components/icons';
import { copyText } from '../copy';

/**
 * The developer surface.
 *
 * Everything here is answerable from view-source and the plugin's code. Putting
 * it one click away is the difference between a plugin a developer can extend
 * on a Friday afternoon and one they have to reverse-engineer first — which on
 * a €149 plugin is most of what "professional" means.
 */
function Developer() {
	const [variant, setVariant] = useState('short');
	const [data, setData] = useState(null);
	const [busy, setBusy] = useState(false);
	const [error, setError] = useState(null);
	const [copied, setCopied] = useState(false);

	const load = async (v) => {
		setBusy(true);
		setError(null);
		try {
			setData(await api.get(`/llms-txt/raw?variant=${v}`));
		} catch (e) {
			setError(e.message);
		} finally {
			setBusy(false);
		}
	};

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

	const copy = async () => {
		if (!data?.body) return;
		if (!(await copyText(data.body))) return;
		setCopied(true);
		setTimeout(() => setCopied(false), 1800);
	};


	return (
		<div className="ars-page">
			<Card
				title={__('Raw output', 'ai-rank-suite')}
				subtitle={__('The exact bytes served at the endpoint, not a rendering of them', 'ai-rank-suite')}
				action={
					<Tabs
						tabs={[
							{ id: 'short', label: 'llms.txt' },
							{ id: 'full', label: 'llms-full.txt' },
						]}
						active={variant}
						onChange={setVariant}
					/>
				}
			>
				{error && <Notice tone="serious">{error}</Notice>}
				{data && (
					<div className="grid gap-3">
						<MetricGrid
							columns={4}
							metrics={[
								{
									id: 'tokens',
									label: __('Tokens', 'ai-rank-suite'),
									hint: __('What a retriever spends reading this variant. Past roughly 100,000 most truncate the file — and the truncation point is not your choice.', 'ai-rank-suite'),
									value: (data.tokens ?? 0).toLocaleString(),
									accent: data.heavy ? 'var(--ars-accent)' : undefined,
								},
								{
									id: 'size',
									label: __('Size', 'ai-rank-suite'),
									hint: __('The exact bytes on the wire.', 'ai-rank-suite'),
									value: (data.bytes / 1024).toFixed(1),
									unit: __('KB', 'ai-rank-suite'),
								},
								{
									id: 'lines',
									label: __('Lines', 'ai-rank-suite'),
									hint: __('Lines of markdown in the served file.', 'ai-rank-suite'),
									value: data.lines,
								},
								{
									id: 'links',
									label: __('Links', 'ai-rank-suite'),
									hint: __('Curated URLs in the file — each with a sentence of meaning attached.', 'ai-rank-suite'),
									value: data.links,
								},
							]}
						/>

						{data.heavy && (
							<Notice tone="warning">
								{__('Past roughly 100,000 tokens most retrievers truncate the file — and the truncation point is not your choice. Reduce the number of pages in the full variant so the cut is one you made.', 'ai-rank-suite')}
							</Notice>
						)}

						{/* Google's PageSpeed report scores this file, and it
						    scores it with three rules. Saying which three, and
						    whether this file passes them, is more useful than
						    letting the customer find out from a red bar. */}
						{data.lighthouse && <LighthouseRow checks={data.lighthouse} />}

						<div className="flex items-center gap-2 flex-wrap">
							<a href={data.url} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1 text-[12.5px]">
								{data.url} <IconExternal size={12} />
							</a>
							<span className="ml-auto flex items-center gap-2">
								{copied && <Badge tone="good">✓ Copied</Badge>}
								<Button variant="ghost" onClick={copy} disabled={busy}>{__('Copy', 'ai-rank-suite')}</Button>
							</span>
						</div>

						<pre
							className="ars-mono m-0 p-3 text-[11.5px]"
							style={{
								background: 'var(--ars-surface-2)',
								border: '1px solid var(--ars-line-soft)',
								color: 'var(--ars-ink)',
								borderRadius: 'var(--ars-r-md)',
								maxHeight: 420,
								overflow: 'auto',
								whiteSpace: 'pre-wrap',
							}}
						>
							{data.body}
						</pre>
					</div>
				)}
			</Card>

			{data && (
				<Card title={__('Hooks', 'ai-rank-suite')} subtitle={__('Everything you can change without touching the plugin', 'ai-rank-suite')}>
					<div className="ars-table-wrap"><table className="ars-table">
						<thead>
							<tr>
								<th>{__('Hook', 'ai-rank-suite')}</th>
								<th>{__('Signature', 'ai-rank-suite')}</th>
								<th>{__('What it changes', 'ai-rank-suite')}</th>
							</tr>
						</thead>
						<tbody>
							{data.hooks.map((h) => (
								<tr key={h.name}>
									<td>
										<code className="ars-mono text-[11.5px]">{h.name}</code>
										<div className="text-[11px] mt-0.5" style={{ color: 'var(--ars-ink-3)' }}>
											{h.type}
										</div>
									</td>
									<td>
										<code className="ars-mono text-[11.5px]">{h.args}</code>
									</td>
									<td className="text-[12.5px]">{h.desc}</td>
								</tr>
							))}
						</tbody>
					</table></div>
				</Card>
			)}

</div>
	);
}


/**
 * Why an owner should care, in the words a buyer uses.
 *
 * Not marketing copy for its own sake: each line names a mechanism the plugin
 * actually implements, so the claim can be checked on the same screen.
 */
const WHY = [
	[
		__('An assistant reads this before it reads your site', 'ai-rank-suite'),
		__('ChatGPT, Claude, Perplexity and Gemini fetch a handful of URLs per answer, not a whole site. llms.txt is the one file that tells them which handful — and it is the only place you get to choose.', 'ai-rank-suite'),
	],
	[
		__('Being quoted correctly is a setting, not luck', 'ai-rank-suite'),
		__('The preferred citation, contact and usage lines below are read verbatim. A model that has been told how to credit you tends to; one that has not will paraphrase your brand into something else.', 'ai-rank-suite'),
	],
	[
		__('Your best page beats your newest page', 'ai-rank-suite'),
		__('Chronology is a blog convention, not a relevance signal. Pinned pages sit at the top of the file, and an assistant that stops reading after ten links has still read the ten you chose.', 'ai-rank-suite'),
	],
	[
		__('It works where a sitemap cannot', 'ai-rank-suite'),
		__('An XML sitemap lists URLs. This lists URLs with a sentence of meaning attached, in the markdown these models were trained on — which is why it survives summarisation.', 'ai-rank-suite'),
	],
];

/**
 * The Agentic Browsing verdict, before the report gives it.
 *
 * Lighthouse scores llms.txt with three regular expressions: a line starting
 * with a single "# ", a markdown link anywhere, and 50 characters. The one
 * that catches people is the middle one — a file listing twenty URLs as plain
 * text passes none of them, because a bare URL is not a markdown link. The
 * plugin writes all three correctly; this says so, and says what they are.
 */
function LighthouseRow({ checks }) {
	const rows = [
		{ id: 'h1', ok: !!checks.h1, label: __('Starts with an H1 heading', 'ai-rank-suite') },
		{ id: 'link', ok: !!checks.link, label: __('Contains a markdown link', 'ai-rank-suite') },
		{ id: 'length', ok: !!checks.length, label: __('Long enough to be a document', 'ai-rank-suite') },
	];
	const all = rows.every((r) => r.ok);
	return (
		<div className="grid gap-1.5">
			<div className="flex items-center gap-2 flex-wrap">
				<span className="t-overline">{__('PageSpeed — Agentic Browsing', 'ai-rank-suite')}</span>
				<Badge tone={all ? 'good' : 'serious'}>{all ? __('Passes', 'ai-rank-suite') : __('Fails', 'ai-rank-suite')}</Badge>
			</div>
			<div className="flex gap-4 flex-wrap text-[12.5px]" style={{ color: 'var(--ars-ink-2)' }}>
				{rows.map((r) => (
					<span key={r.id} className="inline-flex items-center gap-1.5">
						<span aria-hidden style={{ color: r.ok ? 'var(--ars-good)' : 'var(--ars-serious)' }}>{r.ok ? '\u2713' : '\u2717'}</span>
						{r.label}
					</span>
				))}
			</div>
		</div>
	);
}

export default function LlmsTxt({ tab = 'short', onTab }) {
	const [data, setData] = useState(null);
	const [busy, setBusy] = useState(false);
	const [saved, setSaved] = useState(false);
	const [error, setError] = useState(null);

	useEffect(() => {
		api.get('/llms-txt').then(setData).catch((e) => setError(e.message));
	}, []);

	const settings = data?.settings;

	const update = (patch) => setData((d) => ({ ...d, settings: { ...d.settings, ...patch } }));

	const save = async () => {
		setBusy(true);
		setError(null);
		setSaved(false);
		try {
			setData(await api.put('/llms-txt', settings));
			setSaved(true);
			setTimeout(() => setSaved(false), 2500);
		} catch (e) {
			setError(e.message);
		} finally {
			setBusy(false);
		}
	};

	/** The verdict's one button, when the file is off: turn it on, saved immediately. */
	const enable = async () => {
		setBusy(true);
		setError(null);
		try {
			setData(await api.put('/llms-txt', { ...settings, enabled: true }));
		} catch (e) {
			setError(e.message);
		} finally {
			setBusy(false);
		}
	};

	/*
	 * The one-click writer.
	 *
	 * Every page the two files carry gets a summary, the site gets its lead,
	 * both files are rebuilt. One slice per request, driven from here, so the
	 * bar moves and a closed tab loses nothing: the next press resumes.
	 */
	const [write, setWrite] = useState(null);
	const [writing, setWriting] = useState(false);
	const pumpWrite = async () => {
		setWriting(true);
		try {
			for (;;) {
				const next = await api.post('/llms-txt/write/tick', {});
				setWrite(next);
				if (next.state !== 'running') break;
			}
			setData(await api.get('/llms-txt'));
		} catch (e) {
			setError(e.message);
		} finally {
			setWriting(false);
		}
	};
	const writeAll = async (overwrite = false) => {
		setError(null);
		setWriting(true);
		try {
			setWrite(await api.post('/llms-txt/write', { overwrite }));
			await pumpWrite();
		} catch (e) {
			setError(e.message);
			setWriting(false);
		}
	};
	const cancelWrite = async () => {
		try {
			setWrite(await api.post('/llms-txt/write/cancel', {}));
		} catch (e) {
			setError(e.message);
		}
	};
	useEffect(() => {
		api.get('/llms-txt/write').then((w) => {
			setWrite(w);
			if (w && w.state === 'running') pumpWrite();
		}).catch(() => {});
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	const regenerate = async () => {
		setBusy(true);
		try {
			setData(await api.post('/llms-txt/regenerate'));
		} catch (e) {
			setError(e.message);
		} finally {
			setBusy(false);
		}
	};

	if (!data) return <PageState error={error} />;

	const stats = data.stats || {};
	// Assistants read this inside a context window; past roughly 8k tokens the
	// tail is what gets dropped, and the tail is the part nobody checks.
	const heavy = (stats.tokens ?? 0) > 8000;
	const pinned = (settings.key_pages || []).length;

	/**
	 * The screen's own conclusion, before its evidence.
	 *
	 * This screen used to open on a gradient headline about the file and put
	 * the file itself below five cards of configuration. The state of the file
	 * is one of three sentences — off, live, or live-but-too-long — and each
	 * has exactly one thing worth pressing.
	 */
	const verdict = (() => {
		if (!settings.enabled) {
			return {
				tone: 'warning',
				text: __('llms.txt is off — an assistant asking about this site gets nothing.', 'ai-rank-suite'),
				why: __('The file is generated from your published content and served at /llms.txt the moment it is on. The panels below decide what goes into it.', 'ai-rank-suite'),
				action: __('Turn it on', 'ai-rank-suite'),
				onAction: enable,
			};
		}
		if (heavy) {
			return {
				tone: 'warning',
				text: sprintf(__('llms.txt is live, but at %s tokens the tail is at risk.', 'ai-rank-suite'), (stats.tokens ?? 0).toLocaleString()),
				why: __('Past roughly 8,000 tokens many assistants stop reading — and the cut is theirs, not yours. Lower the max items or unpin pages under Generation below, so the cut is one you made.', 'ai-rank-suite'),
				action: __('Open the file', 'ai-rank-suite'),
				onAction: () => window.open(data.url, '_blank', 'noopener'),
			};
		}
		return {
			tone: 'good',
			text: sprintf(/* translators: 1: links, 2: tokens. */ __('llms.txt is live — %1$d curated links, %2$s tokens.', 'ai-rank-suite'), stats.links ?? 0, (stats.tokens ?? 0).toLocaleString()),
			why: __('An assistant fetches a handful of URLs per answer; this file is where you choose the handful. The preview below is the exact bytes served.', 'ai-rank-suite'),
			action: __('Open the file', 'ai-rank-suite'),
			onAction: () => window.open(data.url, '_blank', 'noopener'),
		};
	})();

	/** One save control, repeated per panel, so the button is never in a different fold than the field. */
	const saveRow = (extra = null) => (
		<div className="flex items-center gap-2">
			<Button onClick={save} busy={busy}>{__('Save', 'ai-rank-suite')}</Button>
			{extra}
			{saved && <Badge tone="good">✓ {__('Saved', 'ai-rank-suite')}</Badge>}
		</div>
	);

	return (
		<div className="ars-page">
			{error && <Notice tone="serious">{error}</Notice>}

			<Advisor
				tone={verdict.tone}
				text={verdict.text}
				sub={verdict.why}
				action={verdict.action}
				onAction={verdict.onAction}
				busy={busy}
			/>

			<Card
				title={__('Write everything', 'ai-rank-suite')}
				subtitle={__('One click: a summary for every page in both files, the lead paragraph for the site, and both files rebuilt.', 'ai-rank-suite')}
				action={
					write && write.state === 'running'
						? <Button variant="ghost" onClick={cancelWrite}>{__('Stop', 'ai-rank-suite')}</Button>
						: (
							<div className="flex items-center gap-2">
								<Button onClick={() => writeAll(false)} busy={writing}>{__('Write everything', 'ai-rank-suite')}</Button>
								<Button variant="ghost" onClick={() => writeAll(true)} disabled={writing}>{__('Rewrite all summaries', 'ai-rank-suite')}</Button>
							</div>
						)
				}
			>
				{write && write.state === 'running' ? (
					<Progress
						label={write.current ? sprintf(__('Writing: %s', 'ai-rank-suite'), write.current) : __('Collecting the pages…', 'ai-rank-suite')}
						done={write.done}
						total={write.total}
						note={sprintf(
							/* translators: 1: pages done, 2: pages total, 3: summaries written, 4: summaries kept. */
							__('%1$d of %2$d pages · %3$d written, %4$d kept as they were', 'ai-rank-suite'),
							write.done, write.total, write.written, write.kept
						)}
					/>
				) : write && write.state === 'done' ? (
					<div className="grid gap-2">
						<p className="m-0 text-[13px]">
							{sprintf(
								/* translators: 1: summaries written, 2: kept, 3: failed. */
								__('Done: %1$d summaries written, %2$d kept as they were, %3$d could not be written. Both files are rebuilt.', 'ai-rank-suite'),
								write.written, write.kept, write.failed
							)}{' '}
							{write.ai ? __('Summaries came from the AI engine.', 'ai-rank-suite') : __('No AI engine is connected, so each summary is the page’s own first sentences.', 'ai-rank-suite')}
						</p>
						{write.lead ? <p className="m-0 text-[12.5px]" style={{ color: 'var(--ars-ink-3)' }}>{__('Site lead written:', 'ai-rank-suite')} {write.lead}</p> : null}
						{write.errors && write.errors.length ? <p className="m-0 text-[12.5px]" style={{ color: 'var(--ars-ink-3)' }}>{__('Skipped (no text):', 'ai-rank-suite')} {write.errors.join(', ')}</p> : null}
					</div>
				) : (
					<p className="m-0 text-[13px]" style={{ color: 'var(--ars-ink-3)' }}>
						{__('The files are only as good as the summaries under each link. Most sites have none, so the long file is raw page text and the short one lists titles with a cut-off paragraph. This writes them all: with the AI engine when a key is stored, from each page’s first sentences otherwise. Pages that already have a summary are kept unless you choose to rewrite.', 'ai-rank-suite')}
					</p>
				)}
			</Card>

			{/*
			 * The numbers, in the density every serious tool uses.
			 *
			 * The token count is the best number on this screen — it is the one
			 * that decides whether the tail of the file exists for an assistant
			 * at all — and it used to be buried mid-page in a tile with a
			 * sentence under it. Beside it: the bytes, the links, the pins.
			 */}
			<MetricGrid
				columns={4}
				metrics={[
					{
						id: 'tokens',
						label: __('Tokens', 'ai-rank-suite'),
						hint: __('What an assistant actually spends reading the file. Past roughly 8,000 the tail gets dropped — and the tail is the part nobody checks.', 'ai-rank-suite'),
						value: (stats.tokens ?? 0).toLocaleString(),
						accent: heavy ? 'var(--ars-accent)' : undefined,
						sub: heavy ? __('long — the tail may be truncated', 'ai-rank-suite') : __('inside a context window', 'ai-rank-suite'),
					},
					{
						id: 'size',
						label: __('Size', 'ai-rank-suite'),
						hint: __('The exact bytes served at /llms.txt.', 'ai-rank-suite'),
						value: ((stats.bytes ?? 0) / 1024).toFixed(1),
						unit: __('KB', 'ai-rank-suite'),
						sub: sprintf(_n('%d line', '%d lines', stats.lines ?? 0, 'ai-rank-suite'), stats.lines ?? 0),
					},
					{
						id: 'links',
						label: __('Links listed', 'ai-rank-suite'),
						hint: __('Curated URLs with a sentence of meaning each — the part an XML sitemap cannot do.', 'ai-rank-suite'),
						value: stats.links ?? 0,
					},
					{
						id: 'pinned',
						label: __('Pinned pages', 'ai-rank-suite'),
						hint: __('Placed at the very top of the file, in your order. An assistant that stops after ten links has still read the ten you chose.', 'ai-rank-suite'),
						value: pinned,
						unit: '/ 20',
						sub: pinned ? __('read before everything else', 'ai-rank-suite') : __('nothing pinned yet', 'ai-rank-suite'),
					},
				]}
			/>

			{/*
			 * The file leads. Two of the three tabs are previews and the third
			 * is the developer surface; all three are the point of the screen,
			 * and every one of them used to sit below five cards of settings.
			 */}
			<Card
				title={__('Preview', 'ai-rank-suite')}
				subtitle={__('Exactly what AI crawlers will receive', 'ai-rank-suite')}
				action={
					<Tabs
						tabs={[
							{ id: 'short', label: 'llms.txt' },
							{ id: 'full', label: 'llms-full.txt' },
							{ id: 'dev', label: __('Developer', 'ai-rank-suite') },
						]}
						active={tab}
						onChange={onTab}
					/>
				}
			>
				{tab === 'dev' ? (
					<Developer />
				) : tab === 'short' ? (
					<pre
						className="ars-mono m-0 p-4 ars-r-md overflow-auto"
						style={{ background: 'var(--ars-surface-2)', maxHeight: 560, whiteSpace: 'pre-wrap' }}
					>
						{data.preview}
					</pre>
				) : (
					<div className="text-[12.5px] grid gap-2" style={{ color: 'var(--ars-ink-2)' }}>
						<p className="m-0">{__('The long version contains the', 'ai-rank-suite')}{' '}<strong>{sprintf(_n('full text of up to %d page', 'full text of up to %d pages', Number(settings.full_max_items) || 0, 'ai-rank-suite'), settings.full_max_items)}</strong>{' '}
							{__('as clean markdown — too large for an inline preview.', 'ai-rank-suite')}
						</p>
						<p className="m-0">
							<a href={data.full_url} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1">
								{sprintf(__('Open %s', 'ai-rank-suite'), data.full_url)} <IconExternal size={11} />
							</a>
						</p>
					</div>
				)}
			</Card>

			<LiveCheck />

			{/*
			 * Configuration, folded away from the file it configures. Each
			 * panel's note carries its current state, so the fold only ever
			 * needs opening to change something — and each panel carries its
			 * own Save, so the button is never in a different fold than the
			 * field it saves.
			 */}
			<Panel
				title={__('Generation', 'ai-rank-suite')}
				note={[
					settings.enabled ? __('on', 'ai-rank-suite') : __('off', 'ai-rank-suite'),
					sprintf(__('max %s per section', 'ai-rank-suite'), settings.max_items),
					settings.full_enabled ? __('full variant on', 'ai-rank-suite') : null,
				]
					.filter(Boolean)
					.join(' · ')}
				defaultOpen={!settings.enabled}
			>
				<div className="grid gap-4" style={{ maxWidth: 560 }}>
					<Switch
						checked={!!settings.enabled}
						onChange={(v) => update({ enabled: v })}
						label={__('Serve /llms.txt on this site', 'ai-rank-suite')}
					/>

					<div>
						<label className="block font-medium mb-1">{__('Intro paragraph (optional)', 'ai-rank-suite')}</label>
						<textarea
							rows={3}
							value={settings.intro}
							onChange={(e) => update({ intro: e.target.value })}
							placeholder={__('One or two sentences telling AI systems what this site is about and who it is for.', 'ai-rank-suite')}
						/>
					</div>

					<div>
						<label className="block font-medium mb-1">{__('Included content', 'ai-rank-suite')}</label>
						<div className="flex gap-4">
							{['page', 'post'].map((pt) => (
								<label key={pt} className="inline-flex items-center gap-1.5">
									<input
										type="checkbox"
										checked={settings.post_types.includes(pt)}
										onChange={(e) =>
											update({
												post_types: e.target.checked
													? [...settings.post_types, pt]
													: settings.post_types.filter((x) => x !== pt),
											})
										}
									/>
									{pt === 'page' ? 'Pages' : 'Posts'}
								</label>
							))}
							<label className="inline-flex items-center gap-1.5">
								<input
									type="checkbox"
									checked={!!settings.include_tax}
									onChange={(e) => update({ include_tax: e.target.checked })}
								/>{__('Topics', 'ai-rank-suite')}</label>
						</div>
					</div>

					<div>
						<label className="block font-medium mb-1">{__('Max items per section', 'ai-rank-suite')}</label>
						<input
							type="number"
							min="5"
							max="200"
							value={settings.max_items}
							onChange={(e) => update({ max_items: Number(e.target.value) })}
							style={{ width: 110 }}
						/>
					</div>

					<div className="ars-r-md p-3 grid gap-3" style={{ background: 'var(--ars-surface-2)' }}>
						<Switch
							checked={!!settings.full_enabled}
							onChange={(v) => update({ full_enabled: v })}
							label={__('Also serve /llms-full.txt (long version, full page content)', 'ai-rank-suite')}
						/>
						{settings.full_enabled && (
							<div>
								<label className="block font-medium mb-1">{__('Max pages in full version', 'ai-rank-suite')}</label>
								<input
									type="number"
									min="5"
									max="200"
									value={settings.full_max_items}
									onChange={(e) => update({ full_max_items: Number(e.target.value) })}
									style={{ width: 110 }}
								/>
							</div>
						)}
					</div>

					{saveRow(
						<Button variant="ghost" onClick={regenerate} busy={busy}>{__('Regenerate preview', 'ai-rank-suite')}</Button>
					)}

					<div className="m-0 text-[12px] grid gap-1" style={{ color: 'var(--ars-ink-3)' }}>
						<span>
							<a href={data.url} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1">
								/llms.txt <IconExternal size={11} />
							</a>{' '}
							— curated index (short)
						</span>
						{settings.full_enabled && (
							<span>
								<a href={data.full_url} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1">
									/llms-full.txt <IconExternal size={11} />
								</a>{' '}
								— full page content (long)
							</span>
						)}
						<span>{__('Requires pretty permalinks. AI summaries as descriptions arrive with the AI modules.', 'ai-rank-suite')}</span>
					</div>
				</div>
			</Panel>

			<Panel
				title={__('Identity & citation', 'ai-rank-suite')}
				note={settings.brand || window.airanksuiteData?.siteName || ''}
			>
				<div className="grid gap-3">
					<p className="m-0 t-caption">{__('Read verbatim by the model. Everything here is a sentence you get to write instead of one it invents.', 'ai-rank-suite')}</p>
					<div className="grid gap-3 sm:grid-cols-2">
						<div>
							<label className="block font-medium mb-1 text-[12.5px]">{__('Brand name', 'ai-rank-suite')}</label>
							<input
								type="text"
								placeholder={window.airanksuiteData?.siteName}
								value={settings.brand || ''}
								onChange={(e) => update({ brand: e.target.value })}
							/>
						</div>
						<div>
							<label className="block font-medium mb-1 text-[12.5px]">{__('Preferred citation', 'ai-rank-suite')}</label>
							<input
								type="text"
								placeholder={__('Brand Name (example.com)', 'ai-rank-suite')}
								value={settings.citation || ''}
								onChange={(e) => update({ citation: e.target.value })}
							/>
						</div>
					</div>
					<div>
						<label className="block font-medium mb-1 text-[12.5px]">{__('One-sentence summary', 'ai-rank-suite')}</label>
						<textarea
							rows={2}
							placeholder={__('Independent guides to X for Y.', 'ai-rank-suite')}
							value={settings.summary || ''}
							onChange={(e) => update({ summary: e.target.value })}
						/>
						<div className="text-[11.5px] mt-1" style={{ color: 'var(--ars-ink-3)' }}>
							{__('This becomes the blockquote under your name — the line an assistant repeats when asked what your site is. Write it as the answer to that question, not as a slogan.', 'ai-rank-suite')}
						</div>
					</div>
					<div className="grid gap-3 sm:grid-cols-2">
						<div>
							<label className="block font-medium mb-1 text-[12.5px]">{__('Contact URL', 'ai-rank-suite')}</label>
							<input
								type="text"
								placeholder="https://example.com/contact"
								value={settings.contact || ''}
								onChange={(e) => update({ contact: e.target.value })}
							/>
						</div>
						<div>
							<label className="block font-medium mb-1 text-[12.5px]">{__('Content usage', 'ai-rank-suite')}</label>
							<input
								type="text"
								placeholder={__('Quote freely with a link back.', 'ai-rank-suite')}
								value={settings.license || ''}
								onChange={(e) => update({ license: e.target.value })}
							/>
						</div>
					</div>
					<div className="flex flex-wrap gap-x-6 gap-y-2">
						<Switch
							checked={!!settings.declare_lang}
							onChange={(v) => update({ declare_lang: v })}
							label={__('Declare the site language', 'ai-rank-suite')}
						/>
						<Switch
							checked={!!settings.link_sitemap}
							onChange={(v) => update({ link_sitemap: v })}
							label={__('Link the XML sitemap', 'ai-rank-suite')}
						/>
						<Switch checked={!!settings.link_feed} onChange={(v) => update({ link_feed: v })} label={__('Link the RSS feed', 'ai-rank-suite')} />
					</div>
					{saveRow()}
				</div>
			</Panel>

			<Panel title={__('Pinned pages', 'ai-rank-suite')} note={pinned ? sprintf(__('%d / 20 pinned', 'ai-rank-suite'), pinned) : __('nothing pinned yet', 'ai-rank-suite')}>
				<div className="grid gap-3">
					<p className="m-0 t-caption">
						{__('Placed at the very top, in this order. An assistant that stops reading after ten links has still read the ten you chose.', 'ai-rank-suite')}
					</p>
					{pinned > 0 && (
						<div className="grid gap-1.5">
							{(settings.key_pages || []).map((id, i) => {
								const c = (data.candidates || []).find((x) => x.id === id);
								const move = (to) => {
									const next = [...settings.key_pages];
									if (to < 0 || to >= next.length) return;
									[next[i], next[to]] = [next[to], next[i]];
									update({ key_pages: next });
								};
								return (
									<div
										key={id}
										className="flex items-center justify-between gap-3 ars-r-md px-3 py-2"
										style={{ background: 'var(--ars-surface-2)' }}
									>
										<span className="flex items-center gap-2.5 min-w-0">
											<span className="t-num text-[12px]" style={{ color: 'var(--ars-ink-3)', width: 16 }}>
												{i + 1}
											</span>
											<span className="text-[13px] truncate">{c ? c.title : `#${id}`}</span>
										</span>
										<span className="flex items-center gap-1 shrink-0">
											<button type="button" onClick={() => move(i - 1)} disabled={i === 0} className="ars-move" aria-label={__('Move up', 'ai-rank-suite')}>
												↑
											</button>
											<button
												type="button"
												onClick={() => move(i + 1)}
												disabled={i === settings.key_pages.length - 1}
												className="ars-move"
												aria-label={__('Move down', 'ai-rank-suite')}
											>
												↓
											</button>
											<button
												type="button"
												onClick={() => update({ key_pages: settings.key_pages.filter((x) => x !== id) })}
												className="ars-move"
												aria-label={__('Remove', 'ai-rank-suite')}
											>
												<IconX size={12} />
											</button>
										</span>
									</div>
								);
							})}
						</div>
					)}

					<select
						value=""
						onChange={(e) => {
							const id = Number(e.target.value);
							if (!id) return;
							const cur = settings.key_pages || [];
							if (cur.includes(id) || cur.length >= 20) return;
							update({ key_pages: [...cur, id] });
						}}
						aria-label={__('Pin a page', 'ai-rank-suite')}
					>
						<option value="">{__('Pin a page…', 'ai-rank-suite')}</option>
						{(data.candidates || [])
							.filter((c) => !(settings.key_pages || []).includes(c.id))
							.map((c) => (
								<option key={c.id} value={c.id}>
									{c.title}
								</option>
							))}
					</select>

					<div>
						<label className="block font-medium mb-1 text-[12.5px]">{__('Section heading', 'ai-rank-suite')}</label>
						<input
							type="text"
							placeholder={__('Start here', 'ai-rank-suite')}
							value={settings.key_label || ''}
							onChange={(e) => update({ key_label: e.target.value })}
							style={{ maxWidth: 260 }}
						/>
					</div>
					{saveRow()}
				</div>
			</Panel>

			<Panel
				title={__('Anything the generator cannot know', 'ai-rank-suite')}
				note={settings.extra ? __('custom markdown appended', 'ai-rank-suite') : __('nothing appended', 'ai-rank-suite')}
			>
				<div className="grid gap-3">
					<p className="m-0 t-caption">
						{__('Appended as markdown at the end — products, service areas, pricing, or a note distinguishing you from a similarly named company.', 'ai-rank-suite')}
					</p>
					<textarea
						rows={5}
						className="ars-mono"
						placeholder={'## Coverage\nDubai, Abu Dhabi and the wider UAE.\n\n## Not to be confused with\nExample Corp of Ohio, no relation.'}
						value={settings.extra || ''}
						onChange={(e) => update({ extra: e.target.value })}
					/>
					{saveRow()}
				</div>
			</Panel>

			<Card title={__('Why this file decides whether you are cited', 'ai-rank-suite')} subtitle={__('Four mechanisms, all of them configurable above', 'ai-rank-suite')}>
				<div className="grid gap-3 sm:grid-cols-2">
					{WHY.map(([h, b]) => (
						<div key={h} className="ars-r-md p-4" style={{ background: 'var(--ars-surface-2)' }}>
							<div className="font-semibold text-[13px] flex items-start gap-1.5">
								<IconSpark size={13} />
								{h}
							</div>
							<div className="text-[12px] mt-1" style={{ color: 'var(--ars-ink-2)' }}>
								{b}
							</div>
						</div>
					))}
				</div>
			</Card>
		</div>
	);
}

/**
 * What the site actually serves.
 *
 * The preview above is what this plugin would write. That is not the same
 * thing as what an assistant receives, and the difference is a real and
 * common failure: rewrite rules that never got flushed answer /llms.txt with
 * a 404, a CDN can hold a copy from before the last edit, and a theme's 404
 * template can return HTTP 200 with a page of HTML in it — which looks fine
 * to everything except the crawler trying to parse a text file.
 */
function LiveCheck() {
	const [result, setResult] = useState(null);
	const [busy, setBusy] = useState(false);

	const run = async () => {
		setBusy(true);
		try {
			setResult(await api.post('/llms-txt/verify'));
		} catch (e) {
			setResult({ ok: false, reason: e.message });
		} finally {
			setBusy(false);
		}
	};

	return (
		<Card
			title={__('What the site actually serves', 'ai-rank-suite')}
			subtitle={__('Fetches the real URL and compares it with what this screen would publish', 'ai-rank-suite')}
			action={
				<Button variant="ghost" busy={busy} onClick={run}>{__('Fetch it', 'ai-rank-suite')}</Button>
			}
		>
			{!result && (
				<p className="m-0 text-[13px]" style={{ color: 'var(--ars-ink-2)' }}>
					{__('The preview above is what this plugin would write. Whether that is what a crawler receives depends on rewrite rules, caches and whatever else answers that URL first.', 'ai-rank-suite')}
				</p>
			)}

			{result && !result.ok && <Notice tone="serious">{result.reason}</Notice>}

			{result && result.ok && (
				<div className="grid gap-2">
					{!result.plain && (
						<Notice tone="serious">{__('The URL answered with', 'ai-rank-suite')}{' '}<code>{result.type || __('no content type', 'ai-rank-suite')}</code>{' '}
							{__('instead of text/plain. That is usually a theme 404 template returning HTTP 200 — it looks fine in a browser and is unparseable to a crawler.', 'ai-rank-suite')}
						</Notice>
					)}
					{result.plain && result.matches && (
						<Notice tone="good">
							{sprintf(__('The served file matches this configuration exactly (%s bytes).', 'ai-rank-suite'), result.bytes.toLocaleString())}
						</Notice>
					)}
					{result.plain && !result.matches && (
						<Notice tone="warning">
							{sprintf(__('The served file differs from what this screen would publish — %1$s bytes served against %2$s expected. Almost always a cache holding a copy from before your last change. If it survives a purge, something else is answering that URL.', 'ai-rank-suite'), result.bytes.toLocaleString(), result.expected.toLocaleString())}
						</Notice>
					)}
					<pre className="ars-head-pre is-tall">{result.body}</pre>
				</div>
			)}
		</Card>
	);
}
