import React, { useEffect, useRef, useState } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { api, moduleRunning } from '../api';
import { Card, Button, Badge } from './ui';
import AgencyFloor from './AgencyFloor';

/*
 * "Is the AI actually doing anything?" — answered on the screen everybody
 * opens, instead of only on the Autopilot screen nobody finds.
 *
 * It inherits the rule the operations floor is built on: **it only moves when
 * something is actually happening.** A card that animates whether or not work
 * is running teaches people to stop looking at it. So there are four honest
 * states and each one says a different thing:
 *
 *   no key      → nothing to show, and a way to fix that
 *   running     → what it is on, how far, what it has cost so far
 *   stalled     → a run exists and is not ticking, with the reason and a nudge
 *   idle        → what it did today, and what it would do next
 *
 * Everything below is a real number from /autopilot/status and /ai/usage:
 * the calls are counted, the spend is metered in micro-dollars by the router,
 * and "24 of 71" is the agent's own cursor.
 */

/** Micro-dollars to something a person reads. */
const money = (micro) => {
	const usd = (Number(micro) || 0) / 1000000;
	if (usd === 0) return '$0';
	return usd < 0.01 ? `$${usd.toFixed(3)}` : `$${usd.toFixed(2)}`;
};

const go = (hash) => {
	window.location.hash = hash;
};

export default function AiAtWork() {
	const [status, setStatus] = useState(null);
	const [usage, setUsage] = useState(null);
	const [busy, setBusy] = useState(false);
	const [note, setNote] = useState(null);
	const timer = useRef(null);

	const load = () => {
		// The free edition has neither module; asking would only put a 404
		// in the console, and the card is not drawn without a status anyway.
		if (!moduleRunning('autopilot')) {
			setStatus(false);
			return;
		}
		api.get('/autopilot/status').then(setStatus).catch(() => setStatus(false));
		if (moduleRunning('ai')) api.get('/ai/usage').then(setUsage).catch(() => {});
	};

	useEffect(() => {
		load();
		return () => clearTimeout(timer.current);
	}, []);

	// Poll only while a run is genuinely in flight. An idle card asking the
	// server every few seconds is the same waste as an idle card that spins.
	useEffect(() => {
		clearTimeout(timer.current);
		if (status && status.running) {
			timer.current = setTimeout(load, 4000);
		}
		return () => clearTimeout(timer.current);
	}, [status]);

	// A failed status call means the module is not installed on this edition;
	// the dashboard should not grow an error card for something it never had.
	if (status === false || status === null) return null;

	/*
	 * Without a key this card said nothing the screen above it had not already
	 * said. The headline, the "AI engine" counter and the first of the next
	 * three actions all read "no engine connected"; this card made it four,
	 * and the floor underneath it made it five. One statement is a prompt,
	 * five are noise. So the card appears once there is a key and there is
	 * something to report: what ran, what it cost, what is queued.
	 */
	if (!status.has_key) return null;

	const st = status.state || {};
	const hasKey = !!status.has_key;
	const running = !!status.running;
	const stalled = !!status.stalled && !running && st.total > 0 && !st.finished;
	const done = Number(st.done) || 0;
	const total = Number(st.total) || 0;
	const pct = total > 0 ? Math.min(100, Math.round((done / total) * 100)) : 0;
	const calls = usage?.spend?.today_calls ?? null;
	const spent = usage?.spend?.today ?? null;
	const task = status.tasks?.[status.now?.task] || null;
	/*
	 * A finished run reports what it cost, not what it was expected to cost.
	 *
	 * The estimate is made before the first call, from an assumed page size,
	 * and it stayed on the card for ever afterwards — so a run that had made
	 * four hundred metered calls still advertised the guess. Every call stamps
	 * its real cost with the run id, so once anything has been spent, that is
	 * the number shown, and it is labelled as the measured one.
	 */
	const runSpent = Number(status.spent?.cost_micro) || 0;
	const finishedAt = Number(status.finished) || 0;
	const runOver = total > 0 && !running && finishedAt > 0;
	/*
	 * A site that has never picked a city reports its timezone as "+04:00",
	 * and "since midnight, +04:00" reads like a fault. Only a real zone name
	 * is worth printing.
	 */
	const rawTz = usage?.spend?.timezone || '';
	const tz = /^[+-]\d{2}:\d{2}$/.test(rawTz) ? '' : rawTz;

	const nudge = async () => {
		setBusy(true);
		setNote(null);
		try {
			await api.post('/autopilot/resume', {});
			setNote(__('Picked up again — the next batch runs on the next page view.', 'ai-rank-suite'));
			load();
		} catch (e) {
			setNote(e.message);
		} finally {
			setBusy(false);
		}
	};

	/* ---- the one line at the top, which is the whole point ------------- */
	let headline;
	let tone = 'neutral';
	if (!hasKey) {
		headline = __('No engine connected yet — the AI cannot do anything for you.', 'ai-rank-suite');
	} else if (running) {
		tone = 'good';
		headline = task
			? sprintf(/* translators: 1: task, 2: done, 3: total. */ __('%1$s — %2$s of %3$s', 'ai-rank-suite'), task.label, done.toLocaleString(), total.toLocaleString())
			: sprintf(__('Working — %1$s of %2$s', 'ai-rank-suite'), done.toLocaleString(), total.toLocaleString());
	} else if (stalled) {
		tone = 'warning';
		headline = sprintf(
			/* translators: 1: done, 2: total. */
			__('A run is open at %1$s of %2$s and is not ticking.', 'ai-rank-suite'),
			done.toLocaleString(),
			total.toLocaleString()
		);
	} else if (calls > 0) {
		tone = 'good';
		headline = sprintf(
			/* translators: 1: calls, 2: spend. */
			__('%1$s AI calls today, %2$s spent. Nothing running right now.', 'ai-rank-suite'),
			calls.toLocaleString(),
			money(spent)
		);
	} else if (runOver) {
		tone = 'good';
		headline = sprintf(
			/* translators: 1: pages done, 2: total. */
			__('Last run finished: %1$s of %2$s pages. Nothing running right now.', 'ai-rank-suite'),
			done.toLocaleString(),
			total.toLocaleString()
		);
	} else {
		headline = __('The engine is connected and idle.', 'ai-rank-suite');
	}

	return (
		<Card
			title={__('The AI at work', 'ai-rank-suite')}
			subtitle={__('What the agent is doing on this site, and what it has cost — counted, not estimated', 'ai-rank-suite')}
			action={hasKey
				? <Badge tone={running ? 'good' : 'neutral'}>{running ? __('running', 'ai-rank-suite') : __('idle', 'ai-rank-suite')}</Badge>
				: <Badge tone="warning">{__('no key', 'ai-rank-suite')}</Badge>}
		>
			<div className="grid gap-3">
				<div className={`ars-aiwork-head is-${tone}`}>
					<span className="ars-aiwork-dot" aria-hidden />
					<span className="ars-aiwork-line">{headline}</span>
				</div>

				{/* A bar only where there is a real cursor to draw. A run that
				    has not started is 0 %, and 0 % is a fact, not a spinner. */}
				{(running || stalled) && total > 0 && (
					<div className="ars-aiwork-bar" role="progressbar" aria-valuenow={pct} aria-valuemin={0} aria-valuemax={100}>
						<i style={{ width: `${pct}%` }} />
					</div>
				)}

				{task?.why && running && <p className="ars-aiwork-why">{task.why}</p>}

				{stalled && (
					<p className="ars-aiwork-why">
						{__('WordPress runs scheduled work on page views, not on the clock, so a quiet site runs it late. This picks it up now.', 'ai-rank-suite')}
					</p>
				)}

				{/*
				  * Every figure says what it counts.
				  *
				  * Four numbers with four two-word labels is a card people
				  * either trust blindly or ignore, and both are bad: "Spent
				  * today" answers neither "since when" nor "measured or
				  * guessed". The note under each one is the difference between
				  * a dashboard and a decoration.
				  */}
				{hasKey && (calls !== null || total > 0) && (
					<div className="ars-aiwork-figures">
						{calls !== null && (
							<div>
								<span>{__('Calls today', 'ai-rank-suite')}</span>
								<strong>{calls.toLocaleString()}</strong>
								<em>
									{tz
										? sprintf(
											/* translators: %s: site timezone name. */
											__('Requests to a model since midnight, %s. One page can take several.', 'ai-rank-suite'),
											tz
										)
										: __('Requests to a model since midnight, in your site timezone. One page can take several.', 'ai-rank-suite')}
								</em>
							</div>
						)}
						{spent !== null && (
							<div>
								<span>{__('Spent today', 'ai-rank-suite')}</span>
								<strong>{money(spent)}</strong>
								<em>{__('Metered from the tokens each call actually used, at your provider’s list price. Not an estimate.', 'ai-rank-suite')}</em>
							</div>
						)}
						{total > 0 && (
							<div>
								<span>{runOver ? __('Last run', 'ai-rank-suite') : __('This run', 'ai-rank-suite')}</span>
								<strong>{done.toLocaleString()} / {total.toLocaleString()}</strong>
								<em>
									{runOver
										? __('Pages the last run got through, out of the queue it planned up front. It is over; nothing is waiting.', 'ai-rank-suite')
										: __('Pages done, out of the queue planned when the run started. The queue cannot grow while it runs.', 'ai-rank-suite')}
								</em>
							</div>
						)}
						{runSpent > 0 ? (
							<div>
								<span>{runOver ? __('That run cost', 'ai-rank-suite') : __('This run so far', 'ai-rank-suite')}</span>
								<strong>{money(runSpent)}</strong>
								<em>{__('Measured: the sum of every call this run made, not the estimate it started with.', 'ai-rank-suite')}</em>
							</div>
						) : st.estimate?.cost ? (
							<div>
								<span>{__('Estimated for the run', 'ai-rank-suite')}</span>
								<strong>{st.estimate.cost}</strong>
								<em>{__('A forecast made before the first call, from an average page. The measured figure replaces it as soon as anything is spent.', 'ai-rank-suite')}</em>
							</div>
						) : null}
					</div>
				)}

				{note && <p className="ars-aiwork-why">{note}</p>}

				<div className="flex items-center gap-2 flex-wrap">
					{!hasKey && <Button onClick={() => go('/ai')}>{__('Connect an engine', 'ai-rank-suite')}</Button>}
					{stalled && <Button busy={busy} onClick={nudge}>{__('Pick it up now', 'ai-rank-suite')}</Button>}
					<Button variant="ghost" onClick={() => go('/autopilot')}>{__('Open the autopilot', 'ai-rank-suite')}</Button>
				</div>

				{/*
				  * The floor itself, without the clockwork column: that belongs
				  * to the screen that owns it. The autopilot screen draws the
				  * whole thing; here it is the short version, and only once
				  * there is a key, so the dashboard does not open with a wall
				  * of desks that are all switched off.
				  */}
				{status.routing && (
					<AgencyFloor routing={status.routing} systems={status.systems} now={status.now} running={running} compact />
				)}
			</div>
		</Card>
	);
}
