import SiteMetricsPanel from '../components/SiteMetricsPanel';
import DashboardTrends from '../components/DashboardTrends';
import React, { useEffect, useState } from 'react';
import { __, _n, sprintf } from '@wordpress/i18n';
import { api } from '../api';
import {
	Card,
	Button,
	Badge,
	Notice,
	Delta,
	LineChart,
	FilterBar,
	Segmented,
	SegmentBar,
	ColumnChart,
	PosBadge,
	Advisor,
	Empty,
	Board,
	SectionTitle,
	PageSkeleton,
} from '../components/ui';

/**
 * Insights.
 *
 * The old version of this screen was ten cards of equal weight, two of which
 * charted the same numbers as the tiles directly above them, and it left the
 * reader to work out what any of it meant. It also told a quiet lie: the
 * content table counted only pages that had already been analysed, so a site
 * with four thousand posts and one analysed page showed "Pages 1" and no posts
 * at all — which reads as "this plugin cannot see my content".
 *
 * Both are fixed by the same idea. State the conclusion first, then show the
 * evidence for it in the order somebody would ask for it, and never present a
 * sample as if it were the whole.
 *
 * The order below is the order of the questions:
 *
 *   1. What should I do?              → the verdict
 *   2. What is happening?             → the metric strip and one chart
 *   3. Where is the leverage?         → the board, promoted to full width
 *   4. What moved, and which way?     → gains and drops
 *   5. Am I being recommended?        → AI visibility and share of voice
 *   6. How much of my site is even    → coverage, which used to be invisible
 *      being measured?
 *   7. Is anything broken underneath? → links and indexing, deliberately last
 */

const PERIODS = [
	{ id: 7, label: __('7 days', 'ai-rank-suite') },
	{ id: 28, label: __('28 days', 'ai-rank-suite') },
	{ id: 90, label: __('90 days', 'ai-rank-suite') },
];

const num = (n) => (n ?? 0).toLocaleString();
const go = (hash) => {
	window.location.hash = hash;
};

export default function Insights() {
	const [days, setDays] = useState(28);
	const [postType, setPostType] = useState('');
	const [data, setData] = useState(null);
	const [loading, setLoading] = useState(true);
	const [error, setError] = useState(null);
	const [metric, setMetric] = useState('clicks');

	const load = (d = days, t = postType, fresh = false) => {
		setLoading(true);
		setError(null);
		api
			.get(`/insights?days=${d}&post_type=${encodeURIComponent(t)}${fresh ? '&refresh=1' : ''}`)
			.then(setData)
			.catch((e) => setError(e.message))
			.finally(() => setLoading(false));
	};

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

	if (!data && loading) return <Card>{__('Reading the period…', 'ai-rank-suite')}</Card>;
	if (error) return <Notice tone="serious">{error}</Notice>;
	if (!data) return <PageSkeleton blocks={4} label={__('Loading insights', 'ai-rank-suite')} />;

	const s = data.search;
	const v = data.visibility;
	const c = data.content;
	const headline = data.headline || {};

	const METRICS = [
		{ id: 'clicks', label: __('Clicks', 'ai-rank-suite'), value: s.clicks, prev: s.prev.clicks, key: 'clicks' },
		{ id: 'impressions', label: __('Impressions', 'ai-rank-suite'), value: s.impressions, prev: s.prev.impressions, key: 'impressions' },
		{ id: 'ctr', label: __('Click-through', 'ai-rank-suite'), value: s.ctr, suffix: '%', key: null },
		{ id: 'position', label: __('Position', 'ai-rank-suite'), value: s.position, prev: s.prev.position, key: 'position', invert: true },
	];

	const active = METRICS.find((m) => m.id === metric) || METRICS[0];

	// What feeds this screen, and whether it is feeding. Each card below
	// draws from one of these; a source that is not connected used to leave a
	// full-height empty card behind, and five of them stacked read as a broken
	// screen rather than an unconfigured one. The strip says the same thing
	// in one row, and the empty cards are not drawn.
	const sources = [
		{ id: 'gsc', label: __('Search Console', 'ai-rank-suite'), live: !!s.has_data, on: __('clicks, impressions, position', 'ai-rank-suite'), off: __('Connect', 'ai-rank-suite'), href: '#/search-console' },
		{ id: 'analysis', label: __('Page analysis', 'ai-rank-suite'), live: (c.scored || 0) > 0, on: sprintf(__('%1$s of %2$s scored', 'ai-rank-suite'), num(c.scored), num(c.total)), off: __('Score pages', 'ai-rank-suite'), href: '#/audit' },
		{ id: 'sim', label: __('Answer simulation', 'ai-rank-suite'), live: !!v.has_data || !!v.ever, on: v.has_data ? __('runs in this period', 'ai-rank-suite') : __('no runs in this period', 'ai-rank-suite'), off: __('Set up', 'ai-rank-suite'), href: '#/ai-visibility' },
		{ id: 'links', label: __('Link checker', 'ai-rank-suite'), live: !!data.links?.has_data, on: __('links checked', 'ai-rank-suite'), off: __('Run once', 'ai-rank-suite'), href: '#/links' },
		{ id: 'indexing', label: __('Instant indexing', 'ai-rank-suite'), live: (data.activity?.total || 0) > 0, on: sprintf(__('%s submitted', 'ai-rank-suite'), num(data.activity?.total || 0)), off: __('Set up', 'ai-rank-suite'), href: '#/google' },
	];
	const liveCount = sources.filter((x) => x.live).length;

	return (
		<div className="grid gap-4">
			{/* 1 ─ The conclusion, before its evidence — as the advisor strip,
			       so the screen opens the same way the dashboard does. */}
			<Advisor
				tone={headline.tone || 'neutral'}
				text={headline.text}
				sub={headline.why}
				action={headline.action}
				onAction={() => go(`#/${headline.href || 'dashboard'}`)}
			/>

			<FilterBar
				right={
					<div className="flex items-center gap-2">
						{data.cached && <Badge tone="neutral">cached</Badge>}
						<Button variant="ghost" busy={loading} onClick={() => load(days, postType, true)}>{__('Refresh', 'ai-rank-suite')}</Button>
					</div>
				}
			>
				<Segmented options={PERIODS} value={days} onChange={setDays} label={__('Period', 'ai-rank-suite')} />
				<label className="flex items-center gap-2 text-[12px]" style={{ color: 'var(--ars-ink-2)' }}>{__('Content', 'ai-rank-suite')}<select className="ars-select" value={postType} onChange={(e) => setPostType(e.target.value)}>
						<option value="">{__('All types', 'ai-rank-suite')}</option>
						{(data.post_types || []).map((t) => (
							<option key={t.name} value={t.name}>
								{t.label}
							</option>
						))}
					</select>
				</label>
				<span className="t-caption">
					{data.period.from} → {data.period.to} · {sprintf(__('vs. %s', 'ai-rank-suite'), data.period.prev)}
				</span>
			</FilterBar>

			<div className="ars-sources" role="list" aria-label={__('Data sources', 'ai-rank-suite')}>
				<span className="ars-sources-lead">
					{liveCount === sources.length ? __('Every source is live', 'ai-rank-suite') : sprintf(__('%1$d of %2$d sources live', 'ai-rank-suite'), liveCount, sources.length)}
				</span>
				{sources.map((src) => (
					<button
						key={src.id}
						type="button"
						role="listitem"
						className={`ars-source${src.live ? ' is-live' : ''}`}
						onClick={() => go(src.href)}
						title={src.live ? `${src.label}: ${src.on}` : sprintf(/* translators: 1: data source name. 2: call to action. */ __('%1$s is not feeding this screen yet — %2$s', 'ai-rank-suite'), src.label, src.off)}
					>
						<span className="ars-source-dot" aria-hidden />
						<span className="ars-source-label">{src.label}</span>
						<span className="ars-source-state">{src.live ? src.on : src.off + ' →'}</span>
					</button>
				))}
			</div>

			{/* 2 ─ What happened. One chart, driven by whichever metric is
			       selected, instead of four tiles and then two charts repeating
			       two of them. */}
			{s.has_data && (
			<Card flush>
				{/* Four zeroes over an explanation of why they are zero is not a
				    measurement; it is a placeholder that looks like one. With no
				    search data the strip is not drawn at all and the card is the
				    explanation. */}
				{s.has_data && (
				<div className="ars-metricstrip">
					{METRICS.map((m) => (
						<button
							key={m.id}
							type="button"
							className={`ars-metric${metric === m.id ? ' is-active' : ''}`}
							onClick={() => setMetric(m.id)}
						>
							<span className="ars-metric-label">{m.label}</span>
							<span className="ars-metric-value tabular-nums">
								{m.value === null || m.value === undefined ? '—' : num(m.value)}
								{m.suffix && <span className="ars-metric-suffix">{m.suffix}</span>}
							</span>
							{m.prev !== undefined && m.prev !== null && (
								/* Rounded at the point of subtraction, not in the
								   formatter: 12.2 - 7.3 is 4.900000000000002 in
								   binary floating point, and that is what shipped
								   to the screen. */
								<Delta value={Math.round(((m.value ?? 0) - m.prev) * 10) / 10} invert={m.invert} />
							)}
						</button>
					))}
				</div>
				)}

				<div className="px-4 pb-4 pt-1">
					{s.has_data ? (
						<LineChart
							label={active.label}
							color={active.id === 'position' ? 'var(--ars-series-2)' : 'var(--ars-series-1)'}
							data={s.series.map((row) => ({ label: row.label, value: row[active.key || 'clicks'] }))}
							height={200}
							invert={active.id === 'position'}
						/>
					) : null}
				</div>
			</Card>
			)}

			{/* 3 ─ The leverage board, promoted to full width. This is the one
			       thing on the screen that translates directly into work. */}
			<Card
				title={__('Where the leverage is', 'ai-rank-suite')}
				subtitle={__('The same fix repeated across pages, ranked by weight × how many pages fail it', 'ai-rank-suite')}
				action={
					<Button variant="ghost" onClick={() => go('#/content')}>{__('Open content', 'ai-rank-suite')}</Button>
				}
			>
				{(data.issues.top || []).length === 0 ? (
					<Empty
						title={__('Nothing is failing across enough pages to rank', 'ai-rank-suite')}
						action={__('Run the site audit', 'ai-rank-suite')}
						onAction={() => go('#/audit')}
						compact
					>{__('Either the analysed pages pass every check, or not enough of them have been analysed to find a pattern.', 'ai-rank-suite')}</Empty>
				) : (
					<>
						<Board
							items={data.issues.top.map((i) => ({
								id: i.id,
								label: i.label,
								hint: sprintf(__('%1$d failing, %2$d warning · weight %3$s', 'ai-rank-suite'), i.fail, i.warn, i.weight),
								value: i.fail * 2 + i.warn,
								display: i.fail + i.warn,
								unit: __('pages', 'ai-rank-suite'),
								color: i.fail > i.warn ? 'var(--ars-c-red-ink)' : 'var(--ars-accent)',
							}))}
							onItem={() => go('#/content')}
						/>
						<p className="t-caption m-0 mt-3">
							{data.issues.truncated
								? sprintf(__('Measured over %s analysed pages (capped — the newest pages first). Reflects the current state of the site, not the selected period.', 'ai-rank-suite'), num(data.issues.scanned))
								: sprintf(__('Measured over %s analysed pages. Reflects the current state of the site, not the selected period.', 'ai-rank-suite'), num(data.issues.scanned))}
						</p>
					</>
				)}
			</Card>

			{/* 4 ─ Movement — only when there is a ranking record to move. */}
			{s.has_data && (
			<div className="grid gap-4 lg:grid-cols-2 items-stretch">
				<Card title={__('Biggest gains', 'ai-rank-suite')} subtitle={__('Keywords that climbed inside this period', 'ai-rank-suite')} flush>
					<MoverTable rows={data.movers.up} empty={__('No keyword improved inside this period.', 'ai-rank-suite')} />
				</Card>
				<Card title={__('Biggest drops', 'ai-rank-suite')} subtitle={__('Fix these before they cost you the ranking', 'ai-rank-suite')} flush>
					<MoverTable rows={data.movers.down} empty={__('Nothing lost ground.', 'ai-rank-suite')} />
				</Card>
			</div>
			)}

			{/* 5 ─ Whether an assistant recommends you. */}
			{(v.has_data || v.ever) && (
			<>
			<SectionTitle hint={__('The measurement this product exists for', 'ai-rank-suite')}>{__('AI search', 'ai-rank-suite')}</SectionTitle>
			<div className="grid gap-4 lg:grid-cols-2 items-stretch">
				<Card
					title={__('Answer simulation trend', 'ai-rank-suite')}
					subtitle={__('Share of monitored prompts where a simulated assistant answer mentions you', 'ai-rank-suite')}
					action={
						<Button variant="ghost" onClick={() => go('#/ai-visibility')}>{__('Open', 'ai-rank-suite')}</Button>
					}
				>
					{v.has_data ? (
						<>
							<LineChart
								label={__('Mentioned', 'ai-rank-suite')}
								color="var(--ars-series-3)"
								data={v.series.map((row) => ({ label: row.label, value: row.value }))}
								height={160}
								formatValue={(x) => `${x}%`}
							/>
							<div className="grid gap-3 sm:grid-cols-3 mt-3">
								<Mini label={__('Cited with a link', 'ai-rank-suite')} value={v.cited} sub={__('assistant linked to you', 'ai-rank-suite')} />
								<Mini label={__('Positive tone', 'ai-rank-suite')} value={v.positive} sub={__('answers in your favour', 'ai-rank-suite')} />
								<Mini label={__('Negative tone', 'ai-rank-suite')} value={v.negative} sub={__('nothing negative', 'ai-rank-suite')} tone={v.negative > 0 ? 'bad' : null} />
							</div>
						</>
					) : (
						<Empty
							title={v.ever ? __('No runs inside this period', 'ai-rank-suite') : __('No answer simulations yet', 'ai-rank-suite')}
							action={v.ever ? __('Open AI Answer Simulation', 'ai-rank-suite') : __('Set up monitoring', 'ai-rank-suite')}
							onAction={() => go('#/ai-visibility')}
						>
							{v.ever
								? __('There are older runs. Widen the period, or run the check again to add a fresh point to the trend.', 'ai-rank-suite')
								: __('Add the questions your customers actually ask an assistant. Each run records whether you were named, how early, and who was named instead.', 'ai-rank-suite')}
						</Empty>
					)}
				</Card>

				<Card
					title={__('Share of voice', 'ai-rank-suite')}
					subtitle={__('Who else is named in the same answers', 'ai-rank-suite')}
					flush
				>
					{(v.competitors || []).length === 0 ? (
						<Empty title={__('No competitor has been named yet', 'ai-rank-suite')} compact>{__('Once a run finds other brands in the same answers, they are counted here.', 'ai-rank-suite')}</Empty>
					) : (
						<div className="px-4 pb-4 pt-1">
							<Board
								items={v.competitors.map((comp) => ({
									id: comp.name,
									label: comp.name,
									value: comp.count,
									display: `${comp.count}×`,
									color: 'var(--ars-c-teal-ink, var(--ars-c-green-ink))',
								}))}
							/>
						</div>
					)}
				</Card>
			</div>

			{/* 6 ─ How much of the site is actually being measured. This block is
			       new, and it is the answer to "why does this screen look empty
			       on my big site". */}
			</>
			)}

			<SectionTitle hint={__('Everything above describes the analysed part of your site', 'ai-rank-suite')}>{__('Coverage', 'ai-rank-suite')}</SectionTitle>
			<div className="grid gap-4 lg:grid-cols-2 items-stretch">
				<Card
					title={__('How much has been analysed', 'ai-rank-suite')}
					subtitle={sprintf(__('%1$s of %2$s published items', 'ai-rank-suite'), num(c.scored), num(c.total))}
					action={
						c.coverage < 100 && (
							<Button variant="ghost" onClick={() => go('#/audit')}>{__('Continue', 'ai-rank-suite')}</Button>
						)
					}
					flush
				>
					<div className="ars-table-wrap">
						<table className="ars-table">
							<thead>
								<tr>
									<th>{__('Type', 'ai-rank-suite')}</th>
									<th className="is-num is-narrow">{__('Published', 'ai-rank-suite')}</th>
									<th className="is-num" style={{ width: 150 }}>{__('Analysed', 'ai-rank-suite')}</th>
									<th className="is-num is-narrow">{__('GEO', 'ai-rank-suite')}</th>
									<th className="is-num is-narrow">{__('SEO', 'ai-rank-suite')}</th>
								</tr>
							</thead>
							<tbody>
								{(c.types || []).map((t) => (
									<tr key={t.type}>
										<td className="font-medium">{t.label}</td>
										<td className="is-num is-narrow tabular-nums">{num(t.count)}</td>
										<td className="is-num">
											<div className="flex items-center justify-end gap-2">
												<span className="ars-cov">
													<span
														className="ars-cov-fill"
														style={{
															width: `${t.coverage}%`,
															background:
																t.coverage === 0
																	? 'var(--ars-c-red-ink)'
																	: t.coverage < 60
																		? 'var(--ars-accent)'
																		: 'var(--ars-c-green-ink)',
														}}
													/>
												</span>
												<span className="tabular-nums t-caption" style={{ minWidth: '6ch' }}>
													{num(t.scored)}
												</span>
											</div>
										</td>
										<td className="is-num is-narrow tabular-nums">
											{t.avg_geo === null ? <span style={{ color: 'var(--ars-ink-3)' }}>—</span> : t.avg_geo}
										</td>
										<td className="is-num is-narrow tabular-nums">
											{t.avg_seo === null ? <span style={{ color: 'var(--ars-ink-3)' }}>—</span> : t.avg_seo}
										</td>
									</tr>
								))}
							</tbody>
						</table>
					</div>
					{c.scored < c.total && (
						<p className="t-caption m-0 px-4 pb-4">
							{__('A dash means nothing in that type has been scored yet, which is not the same as scoring zero. On a large site the audit works through the backlog in batches.', 'ai-rank-suite')}
						</p>
					)}
				</Card>

				<Card
					title={__('Score distribution', 'ai-rank-suite')}
					subtitle={sprintf(_n('%s scored page by GEO band — a fat left tail is where the work is', '%s scored pages by GEO band — a fat left tail is where the work is', c.scored, 'ai-rank-suite'), num(c.scored))}
				>
					{c.scored === 0 ? (
						<Empty title={__('Nothing scored yet', 'ai-rank-suite')} action={__('Run the site audit', 'ai-rank-suite')} onAction={() => go('#/audit')}>{__('The distribution needs stored analyses to draw. It fills in as the audit works through your content.', 'ai-rank-suite')}</Empty>
					) : (
						<ColumnChart
							data={c.bands.map((band, i) => ({ label: band, value: c.distribution[i] }))}
							series={[{ key: 'value', label: __('Pages', 'ai-rank-suite'), color: 'var(--ars-brand)' }]}
							height={160}
						/>
					)}
				</Card>
			</div>

			{/* 7 ─ Plumbing, deliberately last. */}
			{(data.links?.has_data || (data.activity?.total || 0) > 0) && (
			<>
			<SectionTitle>{__('Underneath', 'ai-rank-suite')}</SectionTitle>
			<div className="grid gap-4 lg:grid-cols-2 items-stretch">
				<Card
					title={__('Link health', 'ai-rank-suite')}
					subtitle={__('Every checked link by HTTP status class', 'ai-rank-suite')}
					action={
						<Button variant="ghost" onClick={() => go('#/links')}>{__('Open checker', 'ai-rank-suite')}</Button>
					}
				>
					{data.links.has_data ? (
						<>
							<SegmentBar
								segments={[
									{ label: __('OK', 'ai-rank-suite'), value: data.links.classes.ok, color: 'var(--ars-c-green-ink)' },
									{ label: __('Redirect', 'ai-rank-suite'), value: data.links.classes.redirect, color: 'var(--ars-accent)' },
									{ label: __('Not found', 'ai-rank-suite'), value: data.links.classes.client, color: 'var(--ars-c-red-ink)' },
									{ label: __('Server error', 'ai-rank-suite'), value: data.links.classes.server, color: '#8b1d24' },
									{ label: __('Unreachable', 'ai-rank-suite'), value: data.links.classes.unreachable, color: 'var(--ars-ink-3)' },
								]}
							/>
							<p className="t-caption m-0 mt-2">
								{num(data.links.internal)} internal · {num(data.links.external)} external
							</p>
							{(data.links.worst || []).length > 0 && (
								<div className="ars-table-wrap mt-3">
									<table className="ars-table">
										<thead>
											<tr>
												<th>{__('Most-linked broken URL', 'ai-rank-suite')}</th>
												<th className="is-num is-narrow">{__('Status', 'ai-rank-suite')}</th>
												<th className="is-num is-narrow">{__('Uses', 'ai-rank-suite')}</th>
											</tr>
										</thead>
										<tbody>
											{data.links.worst.map((w) => (
												<tr key={w.url}>
													<td className="truncate ars-mono text-[11.5px]">{w.url}</td>
													<td className="is-num is-narrow">
														<Badge tone={w.status === 0 ? 'neutral' : 'serious'}>
															{w.status === 0 ? __('no reply', 'ai-rank-suite') : w.status}
														</Badge>
													</td>
													<td className="is-num is-narrow tabular-nums">{w.refs}</td>
												</tr>
											))}
										</tbody>
									</table>
								</div>
							)}
						</>
					) : (
						<Empty title={__('No links have been checked yet', 'ai-rank-suite')} action={__('Open the link checker', 'ai-rank-suite')} onAction={() => go('#/links')}>{__('The checker crawls the links inside your own content and records what each one answers.', 'ai-rank-suite')}</Empty>
					)}
				</Card>

				<Card
					title={__('Indexing activity', 'ai-rank-suite')}
					subtitle={__('URLs submitted per day — proof search engines were told about your changes', 'ai-rank-suite')}
					action={<Badge tone={data.activity.total > 0 ? 'good' : 'neutral'}>{num(data.activity.total)} submitted</Badge>}
				>
					{data.activity.total > 0 ? (
						<ColumnChart
							data={data.activity.series}
							series={[
								{ key: 'indexnow', label: __('IndexNow', 'ai-rank-suite'), color: 'var(--ars-brand)' },
								{ key: 'google', label: __('Google Indexing API', 'ai-rank-suite'), color: 'var(--ars-c-green-ink)' },
							]}
							height={150}
						/>
					) : (
						<Empty title={__('Nothing submitted in this period', 'ai-rank-suite')} action={__('Set up instant indexing', 'ai-rank-suite')} onAction={() => go('#/google')}>
							{__('IndexNow tells Bing, Yandex, Seznam and Naver the moment a page changes. The Google Indexing API covers job postings and live streams.', 'ai-rank-suite')}
						</Empty>
					)}
				</Card>
			</div>
			</>
			)}

			{/* 8 ─ The full metric inventory and the coverage history, moved
			       here from the dashboard (1.0 Phase 2): the dashboard opens on
			       the verdict; the reference numbers live with the analytics. */}
			<SiteMetricsPanel />
			<DashboardTrends charts={['scored']} />
		</div>
	);
}

/** Rank movement, as a table rather than a chart — the numbers are the point. */
function MoverTable({ rows, empty }) {
	if (!rows || rows.length === 0) {
		return <Empty title={empty} compact>{__('Nothing to show for this period.', 'ai-rank-suite')}</Empty>;
	}
	return (
		<div className="ars-table-wrap">
			<table className="ars-table">
				<thead>
					<tr>
						<th>{__('Keyword', 'ai-rank-suite')}</th>
						<th className="is-num is-narrow">{__('Was', '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.keyword}>
							<td className="font-medium truncate">{r.keyword}</td>
							<td className="is-num is-narrow tabular-nums" style={{ color: 'var(--ars-ink-3)' }}>
								{r.was}
							</td>
							<td className="is-num is-narrow">
								<PosBadge value={r.now} />
							</td>
							<td className="is-num is-narrow">
								<Delta value={r.delta} invert />
							</td>
						</tr>
					))}
				</tbody>
			</table>
		</div>
	);
}

/** A small labelled number used under the visibility chart. */
function Mini({ label, value, sub, tone }) {
	return (
		<div className="ars-mini">
			<span className="ars-mini-label">{label}</span>
			<span className="ars-mini-value tabular-nums" style={tone === 'bad' ? { color: 'var(--ars-c-red-ink)' } : undefined}>
				{value ?? 0}
			</span>
			<span className="ars-mini-sub">{sub}</span>
		</div>
	);
}
