import { __, _n, sprintf } from '@wordpress/i18n';
import React, { useEffect, useState } from 'react';
import { api } from '../api';
import { usableTabs } from '../App';
import ScreenVerdict from '../components/ScreenVerdict';
import Bing from './Bing';
import { Card, Button, Badge, Notice, LineChart, Tabs, SegmentBar, ChipBar, MetricGrid, Panel, PageState } from '../components/ui';
import Explain from '../components/Explain';
import RankTracker from './RankTracker';

function Setup({ status, onStatus }) {
	const [clientId, setClientId] = useState('');
	const [clientSecret, setClientSecret] = useState('');
	const [busy, setBusy] = useState(false);
	const [error, setError] = useState(null);

	const saveCreds = async () => {
		setBusy(true);
		setError(null);
		try {
			onStatus(await api.put('/gsc/credentials', { client_id: clientId, client_secret: clientSecret }));
		} catch (e) {
			setError(e.message);
		} finally {
			setBusy(false);
		}
	};

	const connect = async () => {
		setBusy(true);
		setError(null);
		try {
			const { url } = await api.get('/gsc/connect-url');
			window.location.href = url;
		} catch (e) {
			setError(e.message);
			setBusy(false);
		}
	};

	const [advanced, setAdvanced] = useState(!status.signin_available);
	const signIn = async () => {
		setBusy(true);
		setError(null);
		try {
			const { url } = await api.get('/gsc/signin-url');
			window.location.href = url;
		} catch (e) {
			setError(e.message);
			setBusy(false);
		}
	};

	return (
		<Card
			title={__('Connect Google', 'ai-rank-suite')}
			subtitle={
				status.signin_available
					? __('One sign-in connects Search Console and Analytics — read-only, revocable any time in your Google account', 'ai-rank-suite')
					: __('Your data, your Google Cloud project — no third-party proxy', 'ai-rank-suite')
			}
		>
			{status.signin_available && (
				<div className="ars-signin">
					<button type="button" className="ars-google-btn" onClick={signIn} disabled={busy}>
						<svg width="18" height="18" viewBox="0 0 48 48" aria-hidden>
							<path fill="#EA4335" d="M24 9.5c3.5 0 6.6 1.2 9.1 3.6l6.8-6.8C35.8 2.5 30.3 0 24 0 14.6 0 6.5 5.4 2.6 13.3l7.9 6.1C12.4 13.6 17.7 9.5 24 9.5z" />
							<path fill="#4285F4" d="M46.5 24.5c0-1.6-.1-3.1-.4-4.5H24v9h12.7c-.6 3-2.3 5.5-4.8 7.2l7.5 5.8c4.4-4 7.1-10 7.1-17.5z" />
							<path fill="#FBBC05" d="M10.5 28.6A14.5 14.5 0 0 1 9.7 24c0-1.6.3-3.1.8-4.6l-7.9-6.1A24 24 0 0 0 0 24c0 3.9.9 7.5 2.6 10.7l7.9-6.1z" />
							<path fill="#34A853" d="M24 48c6.5 0 11.9-2.1 15.9-5.8l-7.5-5.8c-2.1 1.4-4.9 2.3-8.4 2.3-6.3 0-11.6-4.1-13.5-9.9l-7.9 6.1C6.5 42.6 14.6 48 24 48z" />
						</svg>
						{busy ? __('Opening Google…', 'ai-rank-suite') : __('Sign in with Google', 'ai-rank-suite')}
					</button>
					<p className="m-0 t-caption">
						{__('Google asks you to allow read access to Search Console and Analytics; nothing is written to your account. Tokens are stored encrypted on this site. Prefer your own Cloud project?', 'ai-rank-suite')}{' '}
						<button type="button" className="ars-linkbtn" onClick={() => setAdvanced((v) => !v)}>
							{advanced ? __('Hide the manual setup', 'ai-rank-suite') : __('Use your own credentials instead', 'ai-rank-suite')}
						</button>
					</p>
					{error && <p className="m-0" style={{ color: 'var(--ars-serious)' }}>{error}</p>}
				</div>
			)}
			{advanced && (
			<>
			<ol className="m-0 pl-5 grid gap-3 text-[13px]">
				<li>
					{__('Open', 'ai-rank-suite')}{' '}
					<a href="https://console.cloud.google.com/apis/credentials" target="_blank" rel="noreferrer">{__('Google Cloud Console → Credentials', 'ai-rank-suite')}</a>{' '}
					{__('and create an', 'ai-rank-suite')} <strong>{__('OAuth client ID', 'ai-rank-suite')}</strong> {__('(type: Web application).', 'ai-rank-suite')}
				</li>
				<li>{__('Enable the', 'ai-rank-suite')} <strong>{__('Search Console API', 'ai-rank-suite')}</strong> {__('for the project (APIs & Services → Library).', 'ai-rank-suite')}
				</li>
				<li>{__('Add this exact redirect URI:', 'ai-rank-suite')}<code
						className="ars-mono block mt-1 px-3 py-2 ars-r-md select-all"
						style={{ background: 'var(--ars-surface-2)' }}
					>
						{status.redirect_uri}
					</code>
				</li>
				<li>{__('Paste the client credentials here:', 'ai-rank-suite')}</li>
			</ol>
			<div className="grid gap-3 mt-3 max-w-[520px]">
				<input
					type="text"
					placeholder={__('Client ID (…apps.googleusercontent.com)', 'ai-rank-suite')}
					value={clientId}
					onChange={(e) => setClientId(e.target.value)}
				/>
				<input
					type="password"
					placeholder={__('Client secret', 'ai-rank-suite')}
					value={clientSecret}
					onChange={(e) => setClientSecret(e.target.value)}
				/>
				<div className="flex gap-2 items-center flex-wrap">
					<Button variant="ghost" onClick={saveCreds} busy={busy} disabled={!clientId || !clientSecret}>{__('Save credentials', 'ai-rank-suite')}</Button>
					<Button onClick={connect} busy={busy} disabled={!status.has_credentials}>{__('Connect with Google →', 'ai-rank-suite')}</Button>
					{status.has_credentials && <Badge tone="good">✓ {__('Credentials stored', 'ai-rank-suite')}</Badge>}
				</div>
				{/* Two greyed-out buttons and no word about why. A disabled control
				    that does not say what would enable it is a dead end. */}
				{!status.has_credentials && (
					<p className="m-0 t-caption">
						{!clientId || !clientSecret
							? __('Paste both the client ID and the secret above to save them — connecting needs stored credentials.', 'ai-rank-suite')
							: __('Save the credentials first; the Google consent screen is opened with them.', 'ai-rank-suite')}
					</p>
				)}
				{error && <p className="m-0" style={{ color: 'var(--ars-serious)' }}>{error}</p>}
			</div>
			</>
			)}
		</Card>
	);
}

function PropertyPicker({ status, onStatus }) {
	const [sites, setSites] = useState(null);
	const [error, setError] = useState(null);

	useEffect(() => {
		api.get('/gsc/sites').then((r) => setSites(r.sites)).catch((e) => setError(e.message));
	}, []);

	return (
		<Card title={__('Choose your property', 'ai-rank-suite')} subtitle={__('Verified Search Console properties of the connected Google account', 'ai-rank-suite')}>
			{error && <Notice tone="serious">{error}</Notice>}
			{!sites && !error && <p style={{ color: 'var(--ars-ink-2)' }}>{__('Loading properties…', 'ai-rank-suite')}</p>}
			{sites && (
				<div className="grid gap-2 max-w-[520px]">
					{sites.length === 0 && <p className="m-0">{__('No verified properties found for this account.', 'ai-rank-suite')}</p>}
					{sites.map((s) => (
						<Button key={s} variant="ghost" onClick={() => api.put('/gsc/property', { site: s }).then(onStatus)}>
							{s}
						</Button>
					))}
				</div>
			)}
		</Card>
	);
}

/** Which series each tile draws, and in which colour. */
const CHART = {
	clicks: { key: 'clicks', label: __('Clicks', 'ai-rank-suite'), color: 'var(--ars-series-1)' },
	impressions: { key: 'impressions', label: __('Impressions', 'ai-rank-suite'), color: 'var(--ars-series-2)' },
	ctr: { key: 'ctr', label: __('CTR', 'ai-rank-suite'), color: 'var(--ars-c-green-ink)' },
	position: { key: 'position', label: __('Average position', 'ai-rank-suite'), color: 'var(--ars-accent)' },
	queries: { key: 'clicks', label: __('Clicks', 'ai-rank-suite'), color: 'var(--ars-series-1)' },
	topten: { key: 'clicks', label: __('Clicks', 'ai-rank-suite'), color: 'var(--ars-series-1)' },
};

function Report({ status, onStatus }) {
	const [metric, setMetric] = useState('clicks');
	const [days, setDays] = useState(28);
	const [data, setData] = useState(null);
	const [error, setError] = useState(null);

	useEffect(() => {
		setData(null);
		api.get(`/gsc/performance?days=${days}`).then(setData).catch((e) => setError(e.message));
	}, [days]);

	const fmt = (n) => (n >= 10000 ? `${(n / 1000).toFixed(1)}k` : String(n));

	return (
		<div className="ars-page">
			{/* The period, and nothing else. Which property is connected and how
			    to disconnect it are settings — they were sitting where the report
			    should start, and Disconnect is not a control that belongs one
			    stray click away from the numbers it would delete. */}
			<div className="flex items-center justify-end gap-3 flex-wrap">
				<Tabs
					tabs={[
						{ id: 7, label: __('7 days', 'ai-rank-suite') },
						{ id: 28, label: __('28 days', 'ai-rank-suite') },
						{ id: 90, label: __('90 days', 'ai-rank-suite') },
					]}
					active={days}
					onChange={setDays}
				/>
			</div>

			{error && <Notice tone="serious">{error}</Notice>}
			{!data && !error && (
				<Card>
					<p className="m-0" style={{ color: 'var(--ars-ink-2)' }}>{__('Fetching Search Console data…', 'ai-rank-suite')}</p>
				</Card>
			)}
			{data && (
				<>
					{/*
					 * Six numbers, one chart.
					 *
					 * Four tiles and then two charts plotting two of those same
					 * four series meant you saw clicks twice before reaching
					 * anything new, and position — the number that actually says
					 * whether the work is landing — was the one metric with no
					 * chart of its own. The tiles select what the chart draws now,
					 * and the two that were missing are here: how many queries you
					 * appear for at all, and how many of them sit on page one.
					 */}
					<MetricGrid
						columns={3}
						active={metric}
						onSelect={setMetric}
						metrics={[
							{
								id: 'clicks',
								label: __('Clicks', 'ai-rank-suite'),
								hint: __('Times somebody chose your result and arrived on the site.', 'ai-rank-suite'),
								value: fmt(data.totals.clicks),
								delta: pct(data.totals.clicks, data.previous?.clicks),
								accent: 'var(--ars-series-1)',
							},
							{
								id: 'impressions',
								label: __('Impressions', 'ai-rank-suite'),
								hint: __('Times a page of yours appeared in a result list at all.', 'ai-rank-suite'),
								value: fmt(data.totals.impressions),
								delta: pct(data.totals.impressions, data.previous?.impressions),
								accent: 'var(--ars-series-2)',
							},
							{
								id: 'ctr',
								label: __('CTR', 'ai-rank-suite'),
								hint: __('Clicks as a share of impressions. A high position with a low CTR is usually a weak title or description.', 'ai-rank-suite'),
								value: `${data.totals.ctr}`,
								unit: '%',
								delta: pct(data.totals.ctr, data.previous?.ctr),
								accent: 'var(--ars-c-green-ink)',
							},
							{
								id: 'position',
								label: __('Average position', 'ai-rank-suite'),
								hint: __('Lower is better. Averaged across every query you appear for, so a flood of new page-nine queries can push it down while nothing got worse.', 'ai-rank-suite'),
								value: data.totals.position,
								// Position improving means the number going down, so
								// the arrow has to be inverted or every gain reads as
								// a loss.
								delta: pct(data.totals.position, data.previous?.position),
								invert: true,
								accent: 'var(--ars-accent)',
							},
							{
								id: 'queries',
								label: __('Queries', 'ai-rank-suite'),
								hint: __('Distinct searches you appeared for in this period. Growth here is reach, whether or not it has turned into clicks yet.', 'ai-rank-suite'),
								value: fmt(data.queries?.length || 0),
								sub: __('in the top set', 'ai-rank-suite'),
							},
							{
								id: 'topten',
								label: __('On page one', 'ai-rank-suite'),
								hint: __('Queries where your average position is 10 or better — the only ones most people ever see.', 'ai-rank-suite'),
								value: fmt((data.queries || []).filter((q) => Number(q.position) <= 10).length),
								sub: __('position 10 or better', 'ai-rank-suite'),
							},
						]}
					/>

					<Card flush>
						{/* Six pixels of gutter, not sixteen: the drawing carries its
						    own axis inset, so the card's padding was a second margin
						    around a picture that already had one. */}
						<div className="px-1.5 pt-3 pb-2">
							<LineChart
								label={CHART[metric]?.label || __('Clicks', 'ai-rank-suite')}
								color={CHART[metric]?.color || 'var(--ars-series-1)'}
								data={data.series.map((d) => ({
									date: d.date,
									value: d[CHART[metric]?.key || 'clicks'],
								}))}
								height={220}
								invert={metric === 'position'}
								formatValue={metric === 'ctr' ? (v) => `${v}%` : undefined}
								bleed
							/>
						</div>
					</Card>

					<GscInsights data={data} fmt={fmt} />

				</>
			)}
		</div>
	);
}

export default function SearchConsole({ tab = 'performance', onTab }) {
	const [status, setStatus] = useState(null);
	const [error, setError] = useState(null);
	const flash = new URLSearchParams((window.location.hash.split('?')[1] || '')); // #/search-console?connected=1

	useEffect(() => {
		api.get('/gsc/status').then(setStatus).catch((e) => setError(e.message));
	}, []);

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

	// Three states, one sentence each: no credentials, credentials but not
	// connected, connected to a property. Each names the one next step.
	const verdict = !status.connected && status.signin_available && !status.has_credentials
		? {
				tone: 'neutral',
				text: __('Search Console and Analytics are not connected yet.', 'ai-rank-suite'),
				why: __('One sign-in with Google connects both — read-only, revocable in your Google account at any time. Rank snapshots cannot be backfilled; the trend starts the day you connect.', 'ai-rank-suite'),
			}
		: !status.has_credentials && !status.connected
		? {
				tone: 'neutral',
				text: __('Search Console is not set up — no Google credentials yet.', 'ai-rank-suite'),
				why: __('Clicks, impressions and positions come from your own Search Console property. It takes a client id and secret from Google Cloud once; after that the connection renews itself.', 'ai-rank-suite'),
			}
		: !status.connected
			? {
					tone: 'warning',
					text: __('Credentials are saved but Google has not been authorised yet.', 'ai-rank-suite'),
					why: __('One click on Connect opens Google, you pick the account, and the data starts flowing. Rank snapshots cannot be backfilled — the trend starts the day you connect.', 'ai-rank-suite'),
				}
			: {
					tone: 'good',
					text: sprintf(__('Connected to %s.', 'ai-rank-suite'), status.property || __('your Search Console property', 'ai-rank-suite')),
					why: __('Reports below are read live from Google. Positions are recorded daily so the rank trend can exist later.', 'ai-rank-suite'),
				};

	return (
		<div className="ars-page">
			{flash.get('error') && <Notice tone="serious">{decodeURIComponent(flash.get('error'))}</Notice>}
			<ScreenVerdict {...verdict} />

			{/* Both tabs read the same Search Console connection, so they belong
			    behind one nav item rather than two that each ask you to connect. */}
			{/* Keywords is the rank tracker, which the free edition does not
			    ship — an unfiltered tab answered "no route matched". */}
			{(() => {
				const { tabs: scTabs, active: scActive } = usableTabs(
					[
						{ id: 'performance', label: __('Google', 'ai-rank-suite') },
						{ id: 'keywords', label: __('Keywords', 'ai-rank-suite'), needs: 'rank_tracker' },
						{ id: 'bing', label: __('Bing', 'ai-rank-suite') },
					],
					tab
				);
				if (scActive !== tab) {
					// The hash asked for a tab this build does not have.
					setTimeout(() => onTab(scActive), 0);
				}
				return <Tabs tabs={scTabs} active={scActive} onChange={onTab} />;
			})()}

			{tab === 'bing' ? (
				<Bing />
			) : tab === 'keywords' ? (
				<RankTracker />
			) : (
				<>
					{!status.connected && <Setup status={status} onStatus={setStatus} />}
					{status.connected && !status.property && <PropertyPicker status={status} onStatus={setStatus} />}
					{status.connected && status.property && <Report status={status} onStatus={setStatus} />}

					{/*
					 * The connection, and the way out of it, at page level.
					 *
					 * This panel used to sit inside <Report>, after the charts.
					 * A report that fails or never finishes loading takes the
					 * whole component with it — including the only control that
					 * disconnects the property. So the one screen you would open
					 * *because* the connection is misbehaving was the one screen
					 * that hid the fix. It renders from `status` alone now,
					 * which is what it always described.
					 */}
					{status.connected && status.property && (
						<Panel title={__('Search Console connection', 'ai-rank-suite')} note={status.property}>
							<div className="grid gap-3">
								<div className="flex items-center gap-2 flex-wrap">
									<Badge tone="good">✓ {__('Connected', 'ai-rank-suite')}</Badge>
									<span className="text-[12.5px] ars-mono" style={{ color: 'var(--ars-ink-2)' }}>
										{status.property}
									</span>
								</div>
								<p className="m-0 text-[12px]" style={{ color: 'var(--ars-ink-3)' }}>
									{__('Disconnecting stops the daily snapshots. The history already recorded stays — it cannot be rebuilt from Google, so nothing here deletes it.', 'ai-rank-suite')}
								</p>
								<div>
									<Button variant="danger" onClick={() => api.post('/gsc/disconnect').then(setStatus)}>{__('Disconnect', 'ai-rank-suite')}</Button>
								</div>
							</div>
						</Panel>
					)}
				</>
			)}
		</div>
	);
}

/** Percentage change, or null when there is nothing to compare against. */
function pct(now, before) {
	if (!before || before === 0) return null;
	return Math.round(((now - before) / before) * 1000) / 10;
}

/**
 * The part of Search Console that is worth paying for.
 *
 * The four totals and a top-ten list are the numbers Google hands you. These
 * are the four questions those numbers cannot answer on their own.
 */
function GscInsights({ data, fmt }) {
	const [view, setView] = useState('questions');
	const q = data.questions || { totals: {}, rows: [] };

	return (
		<div className="grid gap-3">
			<ChipBar
				label={__('Look at', 'ai-rank-suite')}
				value={view}
				onChange={setView}
				options={[
					{ id: 'questions', label: __('Questions', 'ai-rank-suite'), count: q.rows?.length || 0 },
					{ id: 'striking', label: __('Nearly page one', 'ai-rank-suite'), count: data.striking?.length || 0 },
					{ id: 'ignored', label: __('Shown, not clicked', 'ai-rank-suite'), count: data.ignored?.length || 0 },
					{ id: 'movement', label: __('Gained & lost', 'ai-rank-suite') },
					{ id: 'all', label: __('Everything', 'ai-rank-suite') },
				]}
			/>

			{view === 'questions' && (
				<>
					<Card
						title={__('Question queries', 'ai-rank-suite')}
						subtitle={__('The queries AI answers consume first — high impressions, and a click-through that falls as the answer moves above the result', 'ai-rank-suite')}
					>
						<MetricGrid
							columns={3}
							metrics={[
								{
									id: 'share',
									label: __('Share of impressions', 'ai-rank-suite'),
									hint: __('How much of everything you are shown for is question-shaped.', 'ai-rank-suite'),
									/* A missing field must read as "not measured", never as
									   the word undefined with a percent sign after it. */
									value: Number.isFinite(Number(q.share)) ? q.share : '—',
									unit: Number.isFinite(Number(q.share)) ? '%' : '',
								},
								{
									id: 'question-ctr',
									label: __('Click-through on questions', 'ai-rank-suite'),
									hint: __('Clicks as a share of impressions, on the question queries alone.', 'ai-rank-suite'),
									value: q.totals?.question?.ctr ?? '—',
									unit: q.totals?.question?.ctr == null ? '' : '%',
									sub: sprintf(__('against %s%% on everything else', 'ai-rank-suite'), q.totals?.other?.ctr ?? 0),
								},
								{
									id: 'question-position',
									label: __('Average position', 'ai-rank-suite'),
									hint: __('Averaged across the question queries. Lower is better.', 'ai-rank-suite'),
									value: q.totals?.question?.position ?? '—',
									sub: sprintf(__('%s distinct questions', 'ai-rank-suite'), (q.totals?.question?.n ?? 0).toLocaleString()),
								},
							]}
						/>

						{q.totals?.question?.ctr > 0 && q.totals?.other?.ctr > 0 && (
							<div className="mt-3">
								<SegmentBar
									segments={[
										{ label: __('Question queries', 'ai-rank-suite'), value: q.totals.question.impressions, color: 'var(--ars-brand)' },
										{ label: __('Everything else', 'ai-rank-suite'), value: q.totals.other.impressions, color: 'var(--ars-surface-3)' },
									]}
								/>
							</div>
						)}
					</Card>

					<Rows title={__('Every question you rank for', 'ai-rank-suite')} rows={q.rows} keyLabel={__('Question', 'ai-rank-suite')} fmt={fmt} />

					<Explain title={__('Why this segment is worth watching on its own', 'ai-rank-suite')}>
						<p>
							{__('A question query is the shape an AI answer eats. When an overview or an assistant answers it above your result, the impression still counts and the click does not — so the signature of AI cannibalisation is this segment\'s click-through falling while its impressions hold or rise. Comparing it against your non-question queries is the closest thing to measuring that from inside Search Console, which does not report it directly.', 'ai-rank-suite')}
						</p>
						<p>
							{__('If it is happening, the response is not to fight for the click. It is to be the source the answer quotes: an answer-first opening, question-shaped sub-headings, and FAQ markup. All three are on the page editor\'s Full report tab.', 'ai-rank-suite')}
						</p>
					</Explain>
				</>
			)}

			{view === 'striking' && (
				<>
					<Card
						title={__('Nearly page one', 'ai-rank-suite')}
						subtitle={__('Positions 4–15, ordered by what three places of improvement would actually be worth', 'ai-rank-suite')}
						flush
					>
						<div className="ars-table-wrap">
							<table className="ars-table">
								<thead>
									<tr>
										<th>{__('Query', 'ai-rank-suite')}</th>
										<th className="is-num is-narrow">{__('Position', 'ai-rank-suite')}</th>
										<th className="is-num is-narrow">{__('Impr.', 'ai-rank-suite')}</th>
										<th className="is-num is-narrow">{__('Clicks', 'ai-rank-suite')}</th>
										<th className="is-num is-narrow">{__('Upside', 'ai-rank-suite')}</th>
									</tr>
								</thead>
								<tbody>
									{(data.striking || []).map((r) => (
										<tr key={r.key}>
											<td className="font-medium">{r.key}</td>
											<td className="is-num is-narrow tabular-nums">{r.position}</td>
											<td className="is-num is-narrow tabular-nums">{fmt(r.impressions)}</td>
											<td className="is-num is-narrow tabular-nums">{r.clicks}</td>
											<td className="is-num is-narrow tabular-nums">
												<b style={{ color: 'var(--ars-brand)' }}>+{r.upside}</b>
											</td>
										</tr>
									))}
								</tbody>
							</table>
						</div>
					</Card>
					<p className="m-0 t-caption">
						{__('Upside is roughly the clicks three positions of improvement would add, from published click-through curves — not a measurement of your site. It is here to rank these against each other, not as a forecast.', 'ai-rank-suite')}
					</p>
				</>
			)}

			{view === 'ignored' && (
				<>
					<Card
						title={__('Shown and not clicked', 'ai-rank-suite')}
						subtitle={__('Ranking well with a click-through far below what that position normally earns — the ranking is fine and the snippet is wrong', 'ai-rank-suite')}
						flush
					>
						<div className="ars-table-wrap">
							<table className="ars-table">
								<thead>
									<tr>
										<th>{__('Page', 'ai-rank-suite')}</th>
										<th className="is-num is-narrow">{__('Position', 'ai-rank-suite')}</th>
										<th className="is-num is-narrow">{__('Impr.', 'ai-rank-suite')}</th>
										<th className="is-num is-narrow">{__('CTR', 'ai-rank-suite')}</th>
										<th className="is-num is-narrow">{__('Usual', 'ai-rank-suite')}</th>
										<th className="is-num is-narrow">{__('Clicks lost', 'ai-rank-suite')}</th>
									</tr>
								</thead>
								<tbody>
									{(data.ignored || []).map((r) => (
										<tr key={r.key}>
											<td className="font-medium" title={r.key}>
												<span className="ars-url">{r.key.replace(/^https?:\/\/[^/]+/, '') || r.key}</span>
											</td>
											<td className="is-num is-narrow tabular-nums">{r.position}</td>
											<td className="is-num is-narrow tabular-nums">{fmt(r.impressions)}</td>
											<td className="is-num is-narrow tabular-nums" style={{ color: 'var(--ars-serious)' }}>
												{r.actual_ctr}%
											</td>
											<td className="is-num is-narrow tabular-nums" style={{ color: 'var(--ars-ink-3)' }}>
												{r.expected_ctr}%
											</td>
											<td className="is-num is-narrow tabular-nums">
												<b>{r.lost}</b>
											</td>
										</tr>
									))}
								</tbody>
							</table>
						</div>
					</Card>
					<p className="m-0 t-caption">
						{__('Every one of these is a title and description problem, which is the cheapest thing on this list to fix. Note that an AI overview sitting above your result depresses click-through at every position, so a page answering a question may appear here without anything being wrong with its snippet.', 'ai-rank-suite')}
					</p>
				</>
			)}

			{view === 'movement' && (
				<div className="grid gap-3 lg:grid-cols-2">
					<MoveTable title={__('Gained', 'ai-rank-suite')} rows={data.movement?.gained || []} fmt={fmt} tone="good" />
					<MoveTable title={__('Lost', 'ai-rank-suite')} rows={data.movement?.lost || []} fmt={fmt} tone="bad" />
				</div>
			)}

			{view === 'all' && (
				<div className="grid gap-3 lg:grid-cols-2">
					<Rows title={__('Top queries', 'ai-rank-suite')} rows={data.queries} keyLabel={__('Query', 'ai-rank-suite')} fmt={fmt} />
					<Rows title={__('Top pages', 'ai-rank-suite')} rows={data.pages} keyLabel={__('Page', 'ai-rank-suite')} fmt={fmt} strip />
				</div>
			)}
		</div>
	);
}

function Rows({ title, rows, keyLabel, fmt, strip = false }) {
	return (
		<Card title={title} flush>
			<div className="ars-table-wrap" style={{ maxHeight: 460 }}>
				<table className="ars-table">
					<thead>
						<tr>
							<th>{keyLabel}</th>
							<th className="is-num is-narrow">{__('Clicks', 'ai-rank-suite')}</th>
							<th className="is-num is-narrow">{__('Impr.', 'ai-rank-suite')}</th>
							<th className="is-num is-narrow">{__('CTR', 'ai-rank-suite')}</th>
							<th className="is-num is-narrow">{__('Pos.', 'ai-rank-suite')}</th>
						</tr>
					</thead>
					<tbody>
						{(rows || []).map((r) => (
							<tr key={r.key}>
								<td className="font-medium" style={{ maxWidth: 300 }} title={r.key}>
									<span className="ars-url">
										{strip ? r.key.replace(/^https?:\/\/[^/]+/, '') || r.key : r.key}
									</span>
								</td>
								<td className="is-num is-narrow tabular-nums">{r.clicks}</td>
								<td className="is-num is-narrow tabular-nums">{fmt(r.impressions)}</td>
								<td className="is-num is-narrow tabular-nums">{r.ctr}%</td>
								<td className="is-num is-narrow tabular-nums">{r.position}</td>
							</tr>
						))}
					</tbody>
				</table>
			</div>
		</Card>
	);
}

function MoveTable({ title, rows, fmt, tone }) {
	return (
		<Card
			title={title}
			subtitle={__('Against the same number of days immediately before', 'ai-rank-suite')}
			flush
		>
			<div className="ars-table-wrap">
				<table className="ars-table">
					<thead>
						<tr>
							<th>{__('Page', 'ai-rank-suite')}</th>
							<th className="is-num is-narrow">{__('Before', 'ai-rank-suite')}</th>
							<th className="is-num is-narrow">{__('Now', 'ai-rank-suite')}</th>
							<th className="is-num is-narrow">{__('Change', 'ai-rank-suite')}</th>
						</tr>
					</thead>
					<tbody>
						{rows.map((r) => (
							<tr key={r.key}>
								<td className="font-medium" title={r.key}>
									<span className="ars-url">{r.key.replace(/^https?:\/\/[^/]+/, '') || r.key}</span>
									{r.gone && <Badge tone="serious">{__('gone', 'ai-rank-suite')}</Badge>}
									{r.new && <Badge tone="brand">{__('new', 'ai-rank-suite')}</Badge>}
								</td>
								<td className="is-num is-narrow tabular-nums">{r.before}</td>
								<td className="is-num is-narrow tabular-nums">{r.clicks}</td>
								<td className="is-num is-narrow tabular-nums">
									<b style={{ color: r.change > 0 ? '#1a7f45' : 'var(--ars-serious)' }}>
										{r.change > 0 ? '+' : ''}
										{r.change}
									</b>
								</td>
							</tr>
						))}
						{rows.length === 0 && (
							<tr>
								<td colSpan={4} style={{ color: 'var(--ars-ink-3)' }}>{__('Nothing moved enough to report.', 'ai-rank-suite')}</td>
							</tr>
						)}
					</tbody>
				</table>
			</div>
		</Card>
	);
}
