import React, { useEffect, useMemo, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { api } from '../api';
import {
	Card,
	Button,
	Badge,
	Notice,
	Field,
	Segmented,
	PageState,
	SectionTitle,
	Empty,
	PosBadge,
} from '../components/ui';
import { IconLink, IconSearch } from '../components/icons';
import KeywordSuggest from '../components/KeywordSuggest';

/**
 * Third-party SEO data vendors.
 *
 * Every card on this screen is a real account at a company that bills per
 * request, so two rules shape the whole design: nothing calls a vendor unless
 * the user pressed something, and every stored key is proven with a live call
 * rather than assumed to work. A "Test" button that only checks the field is
 * non-empty is worse than no button — it says yes and then the first real
 * request fails a week later.
 */

/** How a metric is spelled and formatted, in the order worth reading. */
const METRICS = [
	{ key: 'authority', label: __('Authority', 'ai-rank-suite'), kind: 'score' },
	{ key: 'trust_flow', label: __('Trust Flow', 'ai-rank-suite'), kind: 'score' },
	{ key: 'citation_flow', label: __('Citation Flow', 'ai-rank-suite'), kind: 'score' },
	{ key: 'page_authority', label: __('Page Authority', 'ai-rank-suite'), kind: 'score' },
	{ key: 'visibility_index', label: __('Visibility Index', 'ai-rank-suite'), kind: 'decimal' },
	{ key: 'referring_domains', label: __('Referring domains', 'ai-rank-suite'), kind: 'count' },
	{ key: 'backlinks', label: __('Backlinks', 'ai-rank-suite'), kind: 'count' },
	{ key: 'organic_keywords', label: __('Organic keywords', 'ai-rank-suite'), kind: 'count' },
	{ key: 'organic_traffic', label: __('Est. monthly visits', 'ai-rank-suite'), kind: 'count' },
	{ key: 'spam_score', label: __('Spam score', 'ai-rank-suite'), kind: 'score' },
];

const fmt = (value, kind) => {
	const n = Number(value);
	if (!Number.isFinite(n)) return '–';
	if (kind === 'decimal') return n.toLocaleString(undefined, { maximumFractionDigits: 2 });
	if (kind === 'count') return n.toLocaleString();
	return String(Math.round(n));
};

const ago = (unix) => {
	if (!unix) return '';
	const mins = Math.round((Date.now() / 1000 - unix) / 60);
	if (mins < 1) return __('just now', 'ai-rank-suite');
	if (mins < 60) return `${mins} min ago`;
	const hours = Math.round(mins / 60);
	if (hours < 24) return `${hours} h ago`;
	return `${Math.round(hours / 24)} d ago`;
};

/**
 * The vendor's own mark, from assets/img/providers/{id}.png — square PNGs
 * shipped with the plugin, never recoloured or redrawn (they are trademarks
 * of their owners). A vendor without a file, or a broken image, falls back to
 * an initials tile with a stable hue from the name.
 */
function VendorMark({ id, label }) {
	const [broken, setBroken] = React.useState(false);
	const base = (window.airanksuiteData && window.airanksuiteData.assetsUrl) || '';
	const src = base ? `${base}img/providers/${id}.png` : '';
	if (src && !broken) {
		return (
			<span className="ars-provider-mark is-image" aria-hidden>
				<img src={src} alt="" width={38} height={38} loading="lazy" onError={() => setBroken(true)} />
			</span>
		);
	}
	const initials = label
		.replace(/[^A-Za-z ]/g, '')
		.split(/\s+/)
		.filter(Boolean)
		.slice(0, 2)
		.map((w) => w[0].toUpperCase())
		.join('');
	let h = 0;
	for (const ch of label) h = (h * 31 + ch.charCodeAt(0)) % 360;
	return (
		<span className="ars-provider-mark" style={{ '--mark-h': h }} aria-hidden>
			{initials || '?'}
		</span>
	);
}

function ProviderCard({ provider, domain, onSaved }) {
	const [open, setOpen] = useState(false);
	const [values, setValues] = useState({});
	const [busy, setBusy] = useState('');
	const [result, setResult] = useState(null);
	const [metrics, setMetrics] = useState(provider.metrics || null);
	const [fetched, setFetched] = useState(provider.fetched || 0);
	const [error, setError] = useState(null);

	// The catalogue is refetched after every save; adopt its numbers so a
	// second card's save does not blank this one's reading.
	useEffect(() => {
		setMetrics(provider.metrics || null);
		setFetched(provider.fetched || 0);
	}, [provider.metrics, provider.fetched]);

	const canMetrics = provider.capabilities.includes('metrics');
	const canSerp = provider.capabilities.includes('serp');

	const run = async (name, fn) => {
		setBusy(name);
		setError(null);
		setResult(null);
		try {
			await fn();
		} catch (e) {
			setError(e.message);
		} finally {
			setBusy('');
		}
	};

	const save = () =>
		run('save', async () => {
			const payload = await api.post(`/seo-apis/${provider.id}/credentials`, { values });
			setValues({});
			setOpen(false);
			onSaved(payload.providers);
		});

	const test = () =>
		run('test', async () => {
			setResult(await api.post(`/seo-apis/${provider.id}/test`, {}));
		});

	const refresh = () =>
		run('metrics', async () => {
			const payload = await api.post(`/seo-apis/${provider.id}/metrics`, { domain, force: true });
			setMetrics(payload.metrics);
			setFetched(payload.fetched);
		});

	const disconnect = () =>
		run('forget', async () => {
			const payload = await api.del(`/seo-apis/${provider.id}/credentials`);
			setMetrics(null);
			setFetched(0);
			setResult(null);
			onSaved(payload.providers);
		});

	const shown = METRICS.filter((m) => metrics && metrics[m.key] !== undefined && metrics[m.key] !== null);

	return (
		<div className={`ars-provider${provider.configured ? ' is-connected' : ''}${open ? ' is-open' : ''}`}>
			<div className="ars-provider-head">
				<VendorMark id={provider.id} label={provider.label} />
				<div className="grid gap-0.5 min-w-0 flex-1">
					<div className="flex items-center gap-2 flex-wrap">
						<span className="ars-provider-name">{provider.label}</span>
						{provider.configured ? (
							<span className="ars-provider-state is-on">{__('Connected', 'ai-rank-suite')}</span>
						) : (
							<span className="ars-provider-state">{__('Not connected', 'ai-rank-suite')}</span>
						)}
					</div>
					<div className="ars-provider-caps">
						{canMetrics && <span className="ars-provider-cap is-metrics">{__('Domain authority', 'ai-rank-suite')}</span>}
						{canSerp && <span className="ars-provider-cap is-serp">{__('Live SERP', 'ai-rank-suite')}</span>}
					</div>
				</div>
				<a
					className="ars-provider-docs"
					href={provider.docs}
					target="_blank"
					rel="noreferrer noopener"
					title={__('Vendor documentation', 'ai-rank-suite')}
				>
					↗
				</a>
			</div>
			<p className="ars-provider-blurb">{provider.blurb}</p>

			{error && <Notice tone="serious">{error}</Notice>}
			{result && <Notice tone={result.ok ? 'good' : 'serious'}>{result.message}</Notice>}

			{shown.length > 0 && (
				<div className="ars-vendor-metrics">
					{shown.map((m) => (
						<div key={m.key} className="ars-vendor-metric">
							<span className="ars-vendor-metric-n tabular-nums">{fmt(metrics[m.key], m.kind)}</span>
							<span className="ars-vendor-metric-l">
								{m.key === 'authority' && metrics.authority_label ? metrics.authority_label : m.label}
							</span>
						</div>
					))}
				</div>
			)}
			{fetched > 0 && (
				<span className="t-caption">
					{__('Measured for', 'ai-rank-suite')} {domain} · {ago(fetched)}
				</span>
			)}

			{open && (
				<div className="grid gap-3 pt-1">
					{provider.fields.map((f) => (
						<Field key={f.key} label={f.label} hint={f.hint} htmlFor={`${provider.id}-${f.key}`}>
							<input
								id={`${provider.id}-${f.key}`}
								type="password"
								autoComplete="off"
								placeholder={f.set ? __('Saved — type to replace', 'ai-rank-suite') : ''}
								value={values[f.key] ?? ''}
								onChange={(e) => setValues({ ...values, [f.key]: e.target.value })}
							/>
						</Field>
					))}
					<p className="t-caption" style={{ margin: 0 }}>
						{provider.notes}{' '}
						<a href={provider.docs} target="_blank" rel="noreferrer noopener">
							{__('Vendor documentation', 'ai-rank-suite')} ↗
						</a>
					</p>
					<div className="flex items-center gap-2 flex-wrap">
						<Button onClick={save} busy={busy === 'save'} disabled={Object.keys(values).length === 0}>
							{__('Save credentials', 'ai-rank-suite')}
						</Button>
						<Button variant="ghost" onClick={() => { setOpen(false); setValues({}); }}>
							{__('Cancel', 'ai-rank-suite')}
						</Button>
					</div>
				</div>
			)}

			{!open && (
				<div className="ars-provider-foot">
					<Button variant={provider.configured ? 'ghost' : 'primary'} onClick={() => setOpen(true)}>
						{provider.configured ? __('Edit credentials', 'ai-rank-suite') : __('Connect', 'ai-rank-suite')}
					</Button>
					{provider.configured && (
						<>
							<Button variant="ghost" onClick={test} busy={busy === 'test'}>
								{__('Test', 'ai-rank-suite')}
							</Button>
							{canMetrics && (
								<Button variant="ghost" onClick={refresh} busy={busy === 'metrics'}>
									{metrics ? __('Refresh', 'ai-rank-suite') : __('Fetch metrics', 'ai-rank-suite')}
								</Button>
							)}
							<Button variant="ghost" onClick={disconnect} busy={busy === 'forget'}>
								{__('Disconnect', 'ai-rank-suite')}
							</Button>
						</>
					)}
				</div>
			)}
		</div>
	);
}

/** Ask a live SERP vendor where this site actually ranks for one keyword. */
function RankCheck({ providers, domain }) {
	const usable = providers.filter((p) => p.configured && p.capabilities.includes('serp'));
	const [id, setId] = useState(usable[0]?.id || '');
	const [keyword, setKeyword] = useState('');
	const [location, setLocation] = useState('');
	const [busy, setBusy] = useState(false);
	const [error, setError] = useState(null);
	const [data, setData] = useState(null);

	useEffect(() => {
		if (!usable.some((p) => p.id === id)) setId(usable[0]?.id || '');
	}, [providers]); // eslint-disable-line react-hooks/exhaustive-deps

	if (usable.length === 0) {
		return (
			<Card title={__('Rank check', 'ai-rank-suite')} icon={<IconSearch size={18} />}>
				<Empty
					icon={<IconSearch size={18} />}
					title={__('No live SERP vendor is connected yet', 'ai-rank-suite')}
				>
					{__(
						'Connect DataForSEO, SerpApi, Serper.dev, ValueSERP, Scale SERP or Zenserp above, and this becomes a real-time position check for any keyword — with your own domain highlighted in the results.',
						'ai-rank-suite'
					)}
				</Empty>
			</Card>
		);
	}

	const check = async () => {
		if (!keyword.trim()) return;
		setBusy(true);
		setError(null);
		setData(null);
		try {
			setData(await api.post(`/seo-apis/${id}/serp`, { keyword: keyword.trim(), location }));
		} catch (e) {
			setError(e.message);
		} finally {
			setBusy(false);
		}
	};

	return (
		<Card
			title={__('Rank check', 'ai-rank-suite')}
			subtitle={__('One live search, run through a vendor you have connected. Costs one credit per check.', 'ai-rank-suite')}
			icon={<IconSearch size={18} />}
		>
			<div className="grid gap-3 md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto] items-end">
				<Field label={__('Keyword', 'ai-rank-suite')} htmlFor="airanksuite-serp-kw">
					<input
						id="airanksuite-serp-kw"
						value={keyword}
						placeholder={__('best coffee dubai', 'ai-rank-suite')}
						onChange={(e) => setKeyword(e.target.value)}
						onKeyDown={(e) => {
							if (e.key === 'Enter') check();
						}}
					/>
				</Field>
				<Field
					label={__('Location', 'ai-rank-suite')}
					hint={__('Optional. A place name, or a country code for Serper.', 'ai-rank-suite')}
					htmlFor="airanksuite-serp-loc"
				>
					<input
						id="airanksuite-serp-loc"
						value={location}
						placeholder={__('United Arab Emirates', 'ai-rank-suite')}
						onChange={(e) => setLocation(e.target.value)}
					/>
				</Field>
				<Button onClick={check} busy={busy} disabled={!keyword.trim()}>
					{__('Check', 'ai-rank-suite')}
				</Button>
			</div>

			<div className="mt-3">
				<KeywordSuggest onPick={setKeyword} label={__('Let AI pick a keyword', 'ai-rank-suite')} />
			</div>

			<div className="mt-3">
				<Segmented
					label={__('Vendor', 'ai-rank-suite')}
					value={id}
					onChange={setId}
					options={usable.map((p) => ({ id: p.id, label: p.label }))}
				/>
			</div>

			{error && (
				<div className="mt-3">
					<Notice tone="serious">{error}</Notice>
				</div>
			)}

			{data && (
				<div className="mt-4 grid gap-3">
					<Notice tone={data.position ? 'good' : 'warning'}>
						{data.position
							? `${domain} ${__('ranks at position', 'ai-rank-suite')} ${data.position} ${__('for', 'ai-rank-suite')} “${keyword}”.`
							: `${domain} ${__('is not in the top', 'ai-rank-suite')} ${data.results.length} ${__('for', 'ai-rank-suite')} “${keyword}”.`}
					</Notice>
					<div className="ars-serp-list">
						{data.results.slice(0, 20).map((row) => {
							const mine = row.domain === domain;
							return (
								<div key={`${row.position}-${row.url}`} className={`ars-serp-row${mine ? ' is-mine' : ''}`}>
									<PosBadge value={row.position} />
									<div className="grid gap-0.5 min-w-0">
										<a href={row.url} target="_blank" rel="noreferrer noopener" className="ars-serp-title">
											{row.title || row.url}
										</a>
										<span className="ars-serp-url">{row.domain}</span>
									</div>
								</div>
							);
						})}
					</div>
					{data.results.length > 20 && (
						<span className="t-caption">
							{__('Showing the top 20 of', 'ai-rank-suite')} {data.results.length} {__('results returned.', 'ai-rank-suite')}
						</span>
					)}
				</div>
			)}
		</Card>
	);
}

export default function SeoApis() {
	const [providers, setProviders] = useState(null);
	const [domain, setDomain] = useState('');
	const [error, setError] = useState(null);
	const [filter, setFilter] = useState('all');

	useEffect(() => {
		api
			.get('/seo-apis')
			.then((payload) => {
				setProviders(payload.providers);
				setDomain(payload.domain);
			})
			.catch((e) => setError(e.message));
	}, []);

	const shown = useMemo(
		() => (providers || []).filter((p) => filter === 'all' || p.category === filter),
		[providers, filter]
	);
	const connected = (providers || []).filter((p) => p.configured).length;

	if (!providers) return <PageState error={error} label={__('Loading vendors', 'ai-rank-suite')} />;

	return (
		<div className="grid gap-5">
			<Card
				title={__('SEO data providers', 'ai-rank-suite')}
				subtitle={__(
					'Bring third-party authority scores and live search results into this dashboard. Keys are encrypted on your own server and never leave it except to the vendor they belong to.',
					'ai-rank-suite'
				)}
				icon={<IconLink size={18} />}
				action={
					<Segmented
						value={filter}
						onChange={setFilter}
						options={[
							{ id: 'all', label: __('All', 'ai-rank-suite') },
							{ id: 'authority', label: __('Domain authority', 'ai-rank-suite') },
							{ id: 'serp', label: __('Live SERP', 'ai-rank-suite') },
						]}
					/>
				}
			>
				<div className="flex items-center gap-2 flex-wrap">
					<Badge tone={connected > 0 ? 'good' : 'neutral'}>
						{connected} {__('of', 'ai-rank-suite')} {providers.length} {__('connected', 'ai-rank-suite')}
					</Badge>
					<span className="t-caption">
						{__('Measuring', 'ai-rank-suite')} {domain}
					</span>
				</div>
			</Card>

			<div>
				<SectionTitle hint={__('Each vendor bills you directly. Nothing here calls out until you press a button.', 'ai-rank-suite')}>
					{filter === 'serp'
						? __('Live search results', 'ai-rank-suite')
						: filter === 'authority'
							? __('Domain authority', 'ai-rank-suite')
							: __('All vendors', 'ai-rank-suite')}
				</SectionTitle>
				<div className="ars-provider-grid mt-3">
					{shown.map((p) => (
						<ProviderCard key={p.id} provider={p} domain={domain} onSaved={setProviders} />
					))}
				</div>
			</div>

			<RankCheck providers={providers} domain={domain} />
		</div>
	);
}
