import { __, _n, sprintf } from '@wordpress/i18n';
import React, { useEffect, useState } from 'react';
import { useSettings } from '../useSettings';
import ScreenVerdict from '../components/ScreenVerdict';
import { api, env } from '../api';
import { Card, Button, Switch, Badge, Notice, Tabs, MetricGrid, ChipBar, PageState } from '../components/ui';
import { IconExternal, IconRefresh } from '../components/icons';
import { copyText } from '../copy';

/** A selectable content type or taxonomy, with the count that decides it. */
/**
 * One content type or taxonomy, and what it contributes.
 *
 * The count used to read "135 published", while the header said the sitemap
 * holds 150 URLs — two numbers about the same thing that never add up,
 * because published is not the same as announced: a noindex page, an
 * excluded ID and a non-public type all drop out in between. When the
 * breakdown knows the real figure, the row shows that instead and keeps the
 * published count as the smaller line, so the arithmetic on the screen
 * works out.
 */
function PickRow({ item, checked, onToggle, inSitemap = null }) {
	return (
		<button
			type="button"
			onClick={onToggle}
			className="flex items-center justify-between gap-3 ars-r-lg px-4 py-2.5 text-left cursor-pointer w-full"
			style={{
				background: checked ? 'var(--ars-brand-tonal)' : 'var(--ars-surface-2)',
				border: '1px solid transparent',
				opacity: item.count === 0 && !checked ? 0.6 : 1,
			}}
			aria-pressed={checked}
		>
			<span className="flex items-center gap-2 min-w-0">
				<span aria-hidden style={{ color: checked ? 'var(--ars-brand-tonal-ink)' : 'var(--ars-ink-3)' }}>
					{checked ? '✓' : '○'}
				</span>
				<span className="font-medium text-[13px]" style={{ color: checked ? 'var(--ars-brand-tonal-ink)' : 'var(--ars-ink)' }}>
					{item.label}
				</span>
			</span>
			<span className="text-[12px] tabular-nums shrink-0 text-right" style={{ color: 'var(--ars-ink-3)' }}>
				{item.count === 0 ? (
					__('empty', 'ai-rank-suite')
				) : checked && inSitemap !== null ? (
					<>
						<span style={{ color: 'var(--ars-ink-2)', fontWeight: 600 }}>
							{sprintf(_n('%s URL in the sitemap', '%s URLs in the sitemap', inSitemap, 'ai-rank-suite'), inSitemap.toLocaleString())}
						</span>
						{inSitemap !== item.count && (
							<span className="block text-[11px]">
								{sprintf(__('of %s published', 'ai-rank-suite'), item.count.toLocaleString())}
							</span>
						)}
					</>
				) : (
					sprintf(__('%s published', 'ai-rank-suite'), item.count.toLocaleString())
				)}
			</span>
		</button>
	);
}


/**
 * The raw XML, in the admin.
 *
 * Opening the sitemap in a browser shows the XSL-rendered table, not the file
 * — which is exactly the wrong thing when you are debugging why a URL is or is
 * not in there. This shows the bytes a crawler receives, and counts the entries
 * from the document rather than from the settings, because a file that claims
 * 500 URLs and contains 12 is the bug this screen exists to surface.
 */
function XmlViewer({ files }) {
	const [target, setTarget] = useState({ kind: 'index', type: '', page: 1 });
	const [data, setData] = useState(null);
	const [busy, setBusy] = useState(false);
	const [error, setError] = useState(null);
	const [wrap, setWrap] = useState(true);

	const load = async (t) => {
		setBusy(true);
		setError(null);
		setTarget(t);
		try {
			const q = new URLSearchParams({ kind: t.kind, type: t.type || '', page: String(t.page || 1) });
			setData(await api.get(`/sitemap/preview?${q}`));
		} catch (e) {
			setError(e.message);
			setData(null);
		} finally {
			setBusy(false);
		}
	};

	useEffect(() => {
		load({ kind: 'index', type: '', page: 1 });
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	const copy = () => {
		if (data?.xml) copyText(data.xml);
	};

	const targets = [
		{ key: 'index', label: __('Index', 'ai-rank-suite'), t: { kind: 'index', type: '', page: 1 } },
		...files.map((f) => ({
			key: `${f.kind}:${f.slug}:${f.url}`,
			label: f.label,
			t: {
				kind: f.kind === 'taxonomy' ? 'tax' : f.kind === 'news' || f.kind === 'video' ? f.kind : 'posts',
				type: f.slug,
				page: Number((String(f.url).match(/-(\d+)\.xml$/) || [, 1])[1]) || 1,
			},
		})),
	];

	const current = `${target.kind}|${target.type}|${target.page}`;

	return (
		<div className="grid gap-3">
			{/* Was a hand-rolled row of solid-blue buttons — the third look this
			    product had for "pick one of these". Same chip as Site Audit now. */}
			<ChipBar
				label={__('File', 'ai-rank-suite')}
				value={current}
				onChange={(key) => {
					const hit = targets.find((x) => `${x.t.kind}|${x.t.type}|${x.t.page}` === key);
					if (hit) load(hit.t);
				}}
				options={targets.map((x) => ({ id: `${x.t.kind}|${x.t.type}|${x.t.page}`, label: x.label }))}
			/>

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

			{data && (
				<>
					<div className="flex items-center gap-2 flex-wrap">
						<Badge tone={data.valid ? 'good' : 'serious'}>{data.valid ? <>✓ {__('Valid XML', 'ai-rank-suite')}</> : __('Malformed XML', 'ai-rank-suite')}</Badge>
						<Badge tone="neutral">
							{data.kind === 'index'
								? sprintf(_n('%d file', '%d files', data.files, 'ai-rank-suite'), data.files)
								: sprintf(_n('%d URL', '%d URLs', data.urls, 'ai-rank-suite'), data.urls)}
						</Badge>
						<Badge tone={data.over ? 'serious' : 'neutral'}>{(data.bytes / 1024).toFixed(1)} KB</Badge>
						{data.over && <Notice tone="serious">{__('Over Google’s 50,000-URL / 50 MB limit — lower URLs per file.', 'ai-rank-suite')}</Notice>}
						<span className="ml-auto flex items-center gap-2">
							<Button variant="ghost" onClick={() => setWrap(!wrap)}>
								{wrap ? __('No wrap', 'ai-rank-suite') : __('Wrap', 'ai-rank-suite')}
							</Button>
							<Button variant="ghost" onClick={copy}>{__('Copy XML', 'ai-rank-suite')}</Button>
						</span>
					</div>

					<pre
						className="ars-mono m-0 p-3 text-[11.5px]"
						style={{
							background: 'var(--ars-code-bg)',
							color: 'var(--ars-code-ink)',
							borderRadius: 'var(--ars-r-sm)',
							maxHeight: 460,
							overflow: 'auto',
							whiteSpace: wrap ? 'pre-wrap' : 'pre',
							wordBreak: wrap ? 'break-all' : 'normal',
						}}
					>
						{data.xml}
					</pre>
				</>
			)}
			{busy && !data && <p className="m-0 text-[12.5px]" style={{ color: 'var(--ars-ink-3)' }}>{__('Loading…', 'ai-rank-suite')}</p>}
		</div>
	);
}

export default function Sitemap({ tab = 'index', onTab }) {
	const { data, setData, s, update, save, run, busy, saved, error } = useSettings('/settings/sitemap');

	if (!data) return <PageState error={error} />;
	const files = data.breakdown?.files || [];
	// A type can span several sitemap files; the row wants the total.
	const urlsPerSlug = files.reduce((acc, f) => {
		if (!f.slug) return acc;
		acc[f.slug] = (acc[f.slug] || 0) + (Number(f.urls) || 0);
		return acc;
	}, {});

	// The flush endpoint returns the same payload shape as GET, so the whole
	// page (including the breakdown) refreshes from one call.
	const rebuild = () => run(async () => setData(await api.post('/sitemap/flush', {})));

	const toggleIn = (key, value) =>
		update({ [key]: s[key].includes(value) ? s[key].filter((x) => x !== value) : [...s[key], value] });

	const SaveRow = () => (
		<div className="flex items-center gap-2">
			<Button onClick={save} busy={busy}>{__('Save', 'ai-rank-suite')}</Button>
			{saved && <Badge tone="good">✓ {__('Saved', 'ai-rank-suite')}</Badge>}
		</div>
	);

	const realFiles = files.filter((f) => f.url);

	// The state of the sitemap before its options: is it reachable, how much
	// does it list, and what is the one thing to do if not.
	const urls = Number(data.total_urls || 0);
	const verdict = !data.permalinks
		? {
				tone: 'bad',
				text: __('The sitemap URL cannot work: pretty permalinks are off.', 'ai-rank-suite'),
				why: __('WordPress serves the sitemap under /sitemap.xml only when permalinks are enabled. Until then crawlers get a 404 and every option below is moot.', 'ai-rank-suite'),
				action: __('Open permalink settings', 'ai-rank-suite'),
				onAction: () => {
					window.location.href = (window.airanksuiteData?.adminUrl || '/wp-admin/') + 'options-permalink.php';
				},
			}
		: !s.enabled
			? {
					tone: 'warning',
					text: __('The sitemap is switched off, so nothing is listed for crawlers.', 'ai-rank-suite'),
					why: __('Search engines and AI crawlers discover pages faster from a sitemap than by following links. Turning it on costs nothing.', 'ai-rank-suite'),
				}
			: urls === 0
				? {
						tone: 'warning',
						text: __('The sitemap is live but lists no URLs.', 'ai-rank-suite'),
						why: __('Every content type and taxonomy is unticked below, or nothing is published in the ticked ones.', 'ai-rank-suite'),
					}
				: {
						tone: 'good',
						text: sprintf(/* translators: 1: URL count, 2: sitemap address. */ __('%1$s URLs are listed at %2$s.', 'ai-rank-suite'), urls.toLocaleString(), String(data.url || '').replace(/^https?:\/\//, '')),
						why: __('Submit that address once in Search Console and Bing Webmaster Tools; after that they read it on their own.', 'ai-rank-suite'),
						action: __('Open the sitemap', 'ai-rank-suite'),
						onAction: () => window.open(data.url, '_blank', 'noopener'),
					};

	const tiles = [
					{
						id: 'status',
						label: __('Sitemap', 'ai-rank-suite'),
						hint: __('A sitemap is a promise to a crawler: these URLs exist, they matter, and this is when they last changed.', 'ai-rank-suite'),
						value: s.enabled ? __('Live', 'ai-rank-suite') : __('Off', 'ai-rank-suite'),
						accent: s.enabled ? undefined : 'var(--ars-accent)',
						sub: s.enabled ? __('announced in robots.txt', 'ai-rank-suite') : __('core sitemap is serving instead', 'ai-rank-suite'),
					},
					{
						id: 'urls',
						label: __('URLs listed', 'ai-rank-suite'),
						hint: __('Anything noindexed, password-protected or excluded is left out — this count is what the files actually contain.', 'ai-rank-suite'),
						value: data.total_urls ?? '—',
					},
					{
						id: 'files',
						label: __('Files in the index', 'ai-rank-suite'),
						hint: __('Large sites are split into several files so each one stays fast to fetch and re-crawl.', 'ai-rank-suite'),
						value: realFiles.length,
						sub: sprintf(__('%s URLs per file', 'ai-rank-suite'), s.per_page),
					},
					( data.breakdown?.excluded ?? 0 ) > 0 && {
						id: 'excluded',
						label: __('Excluded by ID', 'ai-rank-suite'),
						hint: __('Excluded by hand on the Content tab. Anything set to noindex is already left out.', 'ai-rank-suite'),
						value: data.breakdown.excluded,
					},
				].filter(Boolean);

	return (
		<div className="ars-page">
			{error && <Notice tone="serious">{error}</Notice>}
			<ScreenVerdict {...verdict} />
			{!data.permalinks && (
				<Notice tone="serious">{__('Pretty permalinks are disabled — the sitemap URL will not work. Enable them under Settings → Permalinks.', 'ai-rank-suite')}</Notice>
			)}
			{!s.enabled && (
				<Notice tone="warning">
					{__('The sitemap is switched off. WordPress will fall back to its own core sitemap, which ignores every setting on this page.', 'ai-rank-suite')}
				</Notice>
			)}

			{/*
			  * The tiles are built before the row so it can be exactly as wide
			  * as it has something to say.
			  *
			  * "Excluded by ID" is zero on almost every site — nobody excludes
			  * pages one at a time, that is what noindex is for — and a quarter
			  * of the most valuable row on the screen was spending itself on a
			  * number that is both always the same and never actionable. It
			  * appears when there is something in it and steps aside when there
			  * is not, and `columns` follows the count so the row never ends in
			  * an empty cell.
			  */}
			<MetricGrid columns={tiles.length} metrics={tiles} />

			<Tabs
				tabs={[
					{ id: 'index', label: __('Index', 'ai-rank-suite') },
					{ id: 'xml', label: __('XML', 'ai-rank-suite') },
					{ id: 'content', label: __('Content', 'ai-rank-suite') },
					{ id: 'special', label: __('Extras', 'ai-rank-suite') },
				]}
				active={tab}
				onChange={onTab}
				right={
					<Button variant="ghost" busy={busy} onClick={rebuild}>
						<IconRefresh size={13} />{__('Rebuild now', 'ai-rank-suite')}</Button>
				}
			/>

			{tab === 'index' && (
				<Card
					title={__('The index, as it ships', 'ai-rank-suite')}
					subtitle={__('The same list a crawler receives at your sitemap URL', 'ai-rank-suite')}
					action={
						<a
							href={data.url}
							target="_blank"
							rel="noreferrer"
							className="text-[12.5px] font-medium inline-flex items-center gap-1"
							style={{ color: 'var(--ars-brand)', textDecoration: 'none' }}
						>
							{data.url.replace(env.homeUrl.replace(/\/$/, ''), '')} <IconExternal size={11} />
						</a>
					}
				>
					{realFiles.length === 0 ? (
						<div className="ars-r-lg px-4 py-5 grid gap-2 place-items-start" style={{ background: 'var(--ars-surface-2)' }}>
							<div className="font-medium text-[13px]">{__('The sitemap is empty', 'ai-rank-suite')}</div>
							<div className="text-[12px]" style={{ color: 'var(--ars-ink-3)' }}>{__('Nothing is selected, or everything selected has no published content yet.', 'ai-rank-suite')}</div>
							<Button variant="tonal" onClick={() => onTab('content')}>{__('Choose what to include', 'ai-rank-suite')}</Button>
						</div>
					) : (
						<div className="ars-table-wrap"><table className="ars-table">
							<thead>
								<tr>
									<th>{__('File', 'ai-rank-suite')}</th>
									<th>{__('Contains', 'ai-rank-suite')}</th>
									<th className="is-num">{__('URLs', 'ai-rank-suite')}</th>
									<th className="is-num">{__('Last change', 'ai-rank-suite')}</th>
								</tr>
							</thead>
							<tbody>
								{realFiles.map((f) => (
									<tr key={f.url}>
										<td>
											<a
												href={f.url}
												target="_blank"
												rel="noreferrer"
												className="ars-mono text-[11.5px] inline-flex items-center gap-1"
											>
												{f.url.replace(env.homeUrl.replace(/\/$/, ''), '')} <IconExternal size={10} />
											</a>
										</td>
										<td className="font-medium">{f.label}</td>
										<td className="is-num">{f.urls === null ? '—' : f.urls}</td>
										<td className="is-num text-[12px]" style={{ color: 'var(--ars-ink-3)' }}>
											{f.lastmod ? new Date(f.lastmod).toLocaleDateString() : '—'}
										</td>
									</tr>
								))}
							</tbody>
						</table></div>
					)}

					{files.some((f) => !f.url) && (
						<div className="mt-3">
							<Notice tone="info">
								{__('Selected but empty, so not listed:', 'ai-rank-suite')}{' '}
								{files
									.filter((f) => !f.url)
									.map((f) => f.label)
									.join(', ')}
								. {__('They appear automatically as soon as they have published content.', 'ai-rank-suite')}
							</Notice>
						</div>
					)}
				</Card>
			)}

			{tab === 'xml' && (
				<Card
					title={__('The XML a crawler receives', 'ai-rank-suite')}
					subtitle={__('Opening the sitemap in a browser shows the styled table, not the file — this shows the bytes', 'ai-rank-suite')}
					action={
						<a
							href={`${env.homeUrl.replace(/\/$/, '')}/sitemap_index.xml`}
							target="_blank"
							rel="noreferrer"
							className="inline-flex items-center gap-1 text-[12.5px]"
						>
							sitemap_index.xml <IconExternal size={12} />
						</a>
					}
				>
					<XmlViewer files={files} />
				</Card>
			)}

			{tab === 'content' && (
				<div className="grid gap-4">
					<Card title={__('Content types', 'ai-rank-suite')} subtitle={__('Pick what a crawler should be told about', 'ai-rank-suite')} action={<SaveRow />}>
						<div className="grid gap-2 sm:grid-cols-2">
							{data.post_types.map((pt) => (
								<PickRow
									key={pt.name}
									item={pt}
									checked={s.post_types.includes(pt.name)}
									inSitemap={urlsPerSlug[pt.name] ?? null}
									onToggle={() => toggleIn('post_types', pt.name)}
								/>
							))}
						</div>
					</Card>

					<Card
						title={__('Taxonomies', 'ai-rank-suite')}
						subtitle={__('Category and tag archives. Worth including when they are real landing pages, not just lists.', 'ai-rank-suite')}
					>
						<div className="grid gap-2 sm:grid-cols-2">
							{data.taxonomies.map((tx) => (
								<PickRow
									key={tx.name}
									item={tx}
									checked={s.taxonomies.includes(tx.name)}
									inSitemap={urlsPerSlug[tx.name] ?? null}
									onToggle={() => toggleIn('taxonomies', tx.name)}
								/>
							))}
						</div>
					</Card>

					<Card title={__('Options', 'ai-rank-suite')} action={<SaveRow />}>
						<div className="grid gap-4">
							<Switch checked={!!s.enabled} onChange={(v) => update({ enabled: v })} label={__('Publish the sitemap', 'ai-rank-suite')} />
							<Switch
								checked={!!s.include_images}
								onChange={(v) => update({ include_images: v })}
								label={__('Include images (helps image search and AI crawlers)', 'ai-rank-suite')}
							/>
							<Switch
								checked={!!s.include_featured}
								onChange={(v) => update({ include_featured: v })}
								label={__('Include the featured image, even when it is not in the content', 'ai-rank-suite')}
							/>

							<div className="grid gap-3 sm:grid-cols-2">
								<div>
									<label className="block font-medium mb-1">{__('URLs per file', 'ai-rank-suite')}</label>
									<input
										type="number"
										min="50"
										max="1000"
										value={s.per_page}
										onChange={(e) => update({ per_page: Number(e.target.value) })}
										style={{ width: 130 }}
									/>
									<div className="text-[11.5px] mt-1" style={{ color: 'var(--ars-ink-3)' }}>{__('Google accepts up to 50,000, but smaller files are fetched and re-crawled faster.', 'ai-rank-suite')}</div>
								</div>
								<div>
									<label className="block font-medium mb-1">{__('Exclude post IDs', 'ai-rank-suite')}</label>
									<input
										type="text"
										placeholder="12, 45, 108"
										value={s.exclude_ids}
										onChange={(e) => update({ exclude_ids: e.target.value })}
									/>
									<div className="text-[11.5px] mt-1" style={{ color: 'var(--ars-ink-3)' }}>{__('Pages set to noindex, or excluded in their own analysis panel, are already left out.', 'ai-rank-suite')}</div>
								</div>
								<div>
									<label className="block font-medium mb-1">{__('Exclude term IDs', 'ai-rank-suite')}</label>
									<input
										type="text"
										value={s.exclude_terms || ''}
										onChange={(e) => update({ exclude_terms: e.target.value })}
										placeholder="7, 19"
										style={{ width: '100%' }}
									/>
									<div className="text-[11.5px] mt-1" style={{ color: 'var(--ars-ink-3)' }}>{__('Category or tag IDs to keep out of the taxonomy sitemaps, comma-separated. The ID is in the URL when you edit the term.', 'ai-rank-suite')}</div>
								</div>
							</div>
						</div>
					</Card>
				</div>
			)}

			{tab === 'special' && (
				<div className="grid gap-4">
					<Card
						title={__('Google News', 'ai-rank-suite')}
						subtitle={__('A separate feed of articles from the last 48 hours — only useful if you are accepted into Google News', 'ai-rank-suite')}
						action={<SaveRow />}
					>
						<div className="grid gap-4">
							<Switch
								checked={!!s.news_enabled}
								onChange={(v) => update({ news_enabled: v })}
								label={__('Publish a Google News sitemap', 'ai-rank-suite')}
							/>
							{s.news_enabled && (
								<>
									<div>
										<label className="block font-medium mb-1">{__('Publication name', 'ai-rank-suite')}</label>
										<input
											type="text"
											placeholder={env.siteName}
											value={s.news_name}
											onChange={(e) => update({ news_name: e.target.value })}
										/>
										<div className="text-[11.5px] mt-1" style={{ color: 'var(--ars-ink-3)' }}>{__('Must match the name registered in Google Publisher Center exactly.', 'ai-rank-suite')}</div>
									</div>
									<div>
										<label className="block font-medium mb-1.5">{__('Which content types count as news', 'ai-rank-suite')}</label>
										<div className="grid gap-2 sm:grid-cols-2">
											{data.post_types.map((pt) => (
												<PickRow
													key={pt.name}
													item={pt}
													checked={s.news_types.includes(pt.name)}
													onToggle={() => toggleIn('news_types', pt.name)}
												/>
											))}
										</div>
									</div>
									<a
										href={data.news_url}
										target="_blank"
										rel="noreferrer"
										className="text-[12.5px] inline-flex items-center gap-1"
									>
										{data.news_url} <IconExternal size={11} />
									</a>
								</>
							)}
						</div>
					</Card>

					<Card
						title={__('Video', 'ai-rank-suite')}
						subtitle={__('YouTube and Vimeo embeds are detected in your content automatically — nothing to tag by hand', 'ai-rank-suite')}
						action={<SaveRow />}
					>
						<div className="grid gap-3">
							<Switch
								checked={!!s.video_enabled}
								onChange={(v) => update({ video_enabled: v })}
								label={__('Publish a video sitemap', 'ai-rank-suite')}
							/>
							{s.video_enabled && (
								<a
									href={data.video_url}
									target="_blank"
									rel="noreferrer"
									className="text-[12.5px] inline-flex items-center gap-1"
								>
									{data.video_url} <IconExternal size={11} />
								</a>
							)}
						</div>
					</Card>
				</div>
			)}
		</div>
	);
}
