import { useState } from 'react';
import {
	ArrowLeft,
	Check,
	Loader2,
	AlertTriangle,
	Sparkles,
	Star,
	ChevronDown,
	ChevronRight,
	ExternalLink,
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { TextInput } from '@/components/ui/text-input';
import FlavioIcon from '@/components/ui/flavio-icon';
import ConfirmDialog from '@/components/ui/confirm-dialog';
import { isAppPaused } from '@/api/client';
import { useInterventionResponse } from '@/features/interventions/useInterventionResponse';
import UpgradeLock from '@/features/interventions/detail/UpgradeLock';

/**
 * Detail for the `dupetitle` / `resolve_dupes` intervention.
 *
 * Several pages share the same <title>, so Google can't tell them apart. Flavio
 * drafts a unique title for every page in each duplicate group; the user edits
 * any of them inline (including the canonical's) and applies, or dismisses the
 * whole block. v1 has no partial acceptance: it's all or nothing.
 *
 * Contract (doc wins over the task): metadata is
 * `clusters:[{ canonical:{page_path,url,current_title,proposed_title},
 *              alternatives:[{page_path,url,current_title,proposed_title}], rationale }]`.
 * userResponse binds by `page_path` (not by index), and only the edited title
 * travels next to it:
 * `{ clusters:[{ canonical:{page_path,proposed_title},
 *                alternatives:[{page_path,proposed_title}] }] }`.
 * The executor discards clusters/alternatives whose `page_path` doesn't match.
 * Apply → status "acknowledge"; Dismiss → status "dismiss" (standard hide).
 *
 * Defensive on metadata: every field is read with a fallback.
 */
const TITLE_MAX = 60;

/** Strip the scheme so a URL reads compactly (keeps the path as-is). */
const displayUrl = (url = '') => url.replace(/^https?:\/\//, '');

/** One editable page title inside a cluster (canonical or alternative). */
const TitleRow = ({ page, isMain, onChange }) => {
	const length = page.title.length;
	const empty = !page.title.trim();
	const over = length > TITLE_MAX;
	const hint = empty
		? 'Add a title so this page is unique.'
		: over
			? 'A bit long; search engines may cut it off.'
			: 'Looks good for search results.';
	const tone = empty
		? 'text-destructive'
		: over
			? 'text-amber-600'
			: 'text-muted-foreground';

	return (
		<div
			className={`rounded-xl p-4 ${
				isMain
					? 'border border-border'
					: 'border border-dashed border-border'
			}`}
		>
			<div className="flex items-center gap-2 mb-2">
				{isMain ? (
					<span className="inline-flex items-center gap-1 rounded-full bg-magenta-50 px-2 py-0.5 small-semibold text-magenta-600">
						<Star className="w-3 h-3 fill-current" />
						Main
					</span>
				) : (
					<span className="inline-flex items-center rounded-full bg-muted px-2 py-0.5 small-medium text-muted-foreground">
						Alt
					</span>
				)}
				{page.url ? (
					<a
						href={page.url}
						target="_blank"
						rel="noopener noreferrer"
						className="inline-flex items-center gap-1 min-w-0 font-mono text-sm text-muted-foreground! hover:text-foreground! hover:underline transition-colors"
					>
						<span className="truncate min-w-0">
							{displayUrl(page.url)}
						</span>
						<ExternalLink className="w-3 h-3 shrink-0" />
					</a>
				) : (
					<span className="font-mono text-sm text-muted-foreground truncate min-w-0">
						{displayUrl(page.url)}
					</span>
				)}
			</div>
			<TextInput
				value={page.title}
				onChange={(e) => onChange(e.target.value)}
				error={empty}
				className="font-semibold!"
				placeholder="Page title"
			/>
			<div className="flex items-center justify-between gap-3 mt-2">
				<span className={`small-regular ${tone}`}>{hint}</span>
				<span
					className={`small-regular ${empty || over ? tone : 'text-muted-foreground'}`}
				>
					{length} / {TITLE_MAX}
				</span>
			</div>
		</div>
	);
};

const DupeTitle = ({ intervention = {}, interventionId, onBack, onResolved }) => {
	const m = intervention.metadata || {};
	const metaClusters = Array.isArray(m.clusters) ? m.clusters : [];
	// Trial ended: the intervention can't be acted on, so its action buttons are
	// swapped for the single "unlock" upgrade CTA.
	const isPaused = isAppPaused();

	const [clusters, setClusters] = useState(() =>
		metaClusters.map((c) => ({
			sharedTitle: c?.canonical?.current_title ?? '',
			rationale: c?.rationale ?? '',
			canonical: {
				pagePath: c?.canonical?.page_path ?? '',
				url: c?.canonical?.url ?? '',
				title: c?.canonical?.proposed_title ?? '',
			},
			alternatives: (Array.isArray(c?.alternatives)
				? c.alternatives
				: []
			).map((a) => ({
				pagePath: a?.page_path ?? '',
				url: a?.url ?? '',
				title: a?.proposed_title ?? '',
			})),
		}))
	);
	// Mirror locationpages: only one cluster open at a time, the first by default.
	const [expandedIndex, setExpandedIndex] = useState(
		metaClusters.length > 0 ? 0 : null
	);

	const {
		pending,
		resolved,
		error,
		confirmingDismiss,
		run,
		confirmDismiss,
		cancelDismiss,
	} = useInterventionResponse(interventionId, { onResolved });

	// `where` is 'canonical' or an alternative index.
	const setTitle = (ci, where, value) =>
		setClusters((prev) =>
			prev.map((c, i) => {
				if (i !== ci) return c;
				if (where === 'canonical') {
					return { ...c, canonical: { ...c.canonical, title: value } };
				}
				return {
					...c,
					alternatives: c.alternatives.map((a, ai) =>
						ai === where ? { ...a, title: value } : a
					),
				};
			})
		);

	const groups = clusters.length;
	const pages = clusters.reduce(
		(sum, c) => sum + 1 + c.alternatives.length,
		0
	);
	const hasEmpty = clusters.some(
		(c) =>
			!c.canonical.title.trim() ||
			c.alternatives.some((a) => !a.title.trim())
	);
	const canApply = groups > 0 && !hasEmpty && !pending && !resolved;

	const apply = () =>
		run('primary', {
			status: 'acknowledge',
			userResponse: {
				clusters: clusters.map((c) => ({
					canonical: {
						page_path: c.canonical.pagePath,
						proposed_title: c.canonical.title.trim(),
					},
					alternatives: c.alternatives.map((a) => ({
						page_path: a.pagePath,
						proposed_title: a.title.trim(),
					})),
				})),
			},
		});

	if (resolved) {
		return (
			<div className="max-w-2xl mx-auto text-center">
				<FlavioIcon className="w-12 h-12 mx-auto mb-4" />
				<h1 className="heading-h2 mt-0! leading-tight mb-3">
					{resolved === 'primary' ? 'All set' : 'Got it'}
				</h1>
				<div className="max-w-md mx-auto">
					<p className="paragraph-regular text-muted-foreground mb-0!">
						{resolved === 'primary'
							? "Great. I'll apply the new titles shortly."
							: "No problem. I'll leave your titles as they are."}
					</p>
				</div>
				{onBack && (
					<Button
						onClick={onBack}
						size="lg"
						className="mt-6 bg-foreground text-background! hover:bg-foreground/90"
					>
						<ArrowLeft />
						Back to your list
					</Button>
				)}
			</div>
		);
	}

	return (
		<div className="max-w-2xl mx-auto">
			<div className="text-center">
				<h1 className="heading-h1 mt-0! leading-tight mb-3">
					Resolve duplicate page titles
				</h1>
				<div className="max-w-xl mx-auto mb-8">
					<p className="paragraph-regular text-muted-foreground mb-0!">
						I found groups of pages with identical titles. I've drafted a
						unique title for each so Google can tell them apart. Edit
						anything before you apply.
					</p>
				</div>
			</div>

			{/* Summary */}
			<div className="rounded-2xl border border-border p-4 mb-5 flex items-start gap-3">
				<span className="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-amber-50 text-amber-500 shrink-0">
					<AlertTriangle className="w-4 h-4" />
				</span>
				<div className="min-w-0">
					<p className="small-semibold text-foreground my-0!">
						{groups} duplicate group{groups === 1 ? '' : 's'} · {pages}{' '}
						page{pages === 1 ? '' : 's'} will get new titles
					</p>
					<p className="small-regular text-muted-foreground my-0! mt-0.5!">
						One page per group stays as the{' '}
						<span className="text-magenta-600 font-medium">Main</span>,
						the others get unique alternatives.
					</p>
				</div>
			</div>

			{/* Clusters — collapsible, one open at a time, first by default */}
			<div className="space-y-3">
				{clusters.map((c, ci) => {
					const expanded = expandedIndex === ci;
					const needsTitle =
						!c.canonical.title.trim() ||
						c.alternatives.some((a) => !a.title.trim());
					const pages = 1 + c.alternatives.length;
					return (
						<div
							key={ci}
							className="rounded-2xl border border-border overflow-hidden"
						>
							<button
								type="button"
								onClick={() =>
									setExpandedIndex(expanded ? null : ci)
								}
								className="w-full flex items-center gap-3 px-5 py-4 text-left cursor-pointer hover:bg-muted/30 transition-colors"
							>
								<span className="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-amber-50 text-amber-500 shrink-0">
									<AlertTriangle className="w-4 h-4" />
								</span>
								<span className="min-w-0 flex-1">
									<span className="block small-semibold uppercase tracking-wide text-muted-foreground truncate">
										Group{' '}
										{String(ci + 1).padStart(2, '0')} ·{' '}
										{pages} pages share this title
									</span>
									<span className="block text-base font-bold text-foreground mt-0.5 truncate">
										"{c.sharedTitle}"
									</span>
								</span>
								{needsTitle && (
									<span className="inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 small-medium text-amber-700 shrink-0">
										Needs title
									</span>
								)}
								<ChevronDown
									className={`w-4 h-4 text-muted-foreground shrink-0 transition-transform ${
										expanded ? 'rotate-180' : ''
									}`}
								/>
							</button>

							{expanded && (
								<div className="px-5 pb-5 border-t border-border pt-5">
									{c.rationale && (
										<div className="flex items-start gap-2 rounded-xl bg-muted/40 p-3 mb-4 small-regular text-muted-foreground">
											<Sparkles className="w-4 h-4 shrink-0 mt-0.5 text-magenta-500" />
											<span>{c.rationale}</span>
										</div>
									)}

									<div className="space-y-3">
										<TitleRow
											page={c.canonical}
											isMain
											onChange={(v) =>
												setTitle(ci, 'canonical', v)
											}
										/>
										{c.alternatives.map((a, ai) => (
											<TitleRow
												key={ai}
												page={a}
												isMain={false}
												onChange={(v) =>
													setTitle(ci, ai, v)
												}
											/>
										))}
									</div>

									{ci < clusters.length - 1 && (
										<div className="flex justify-end mt-4">
											<button
												type="button"
												onClick={() =>
													setExpandedIndex(ci + 1)
												}
												className="inline-flex items-center gap-1 small-medium text-muted-foreground hover:text-foreground transition-colors cursor-pointer"
											>
												Next group
												<ChevronRight className="w-4 h-4" />
											</button>
										</div>
									)}
								</div>
							)}
						</div>
					);
				})}
			</div>

			<div className="flex items-center justify-center gap-3 mt-8">
				{isPaused ? (
					<UpgradeLock />
				) : (
					<>
						<Button
							onClick={apply}
							disabled={!canApply}
							size="lg"
							className="bg-foreground text-background! hover:bg-foreground/90"
						>
							{pending === 'primary' ? (
								<Loader2 className="animate-spin" />
							) : (
								<Check />
							)}
							Apply new titles
						</Button>
						<Button
							onClick={() =>
								run('secondary', {
									status: 'dismiss',
								})
							}
							disabled={!!pending || !!resolved}
							size="lg"
							variant="outline"
						>
							{pending === 'secondary' && (
								<Loader2 className="animate-spin" />
							)}
							Don't apply
						</Button>
					</>
				)}
			</div>

			{!isPaused && (error || hasEmpty) && (
				<p
					className={`small-regular text-center mt-3 mb-0! ${
						error ? 'text-destructive' : 'text-muted-foreground'
					}`}
				>
					{error ||
						'Give every page a title before applying, so none stay duplicated.'}
				</p>
			)}
			{!isPaused && (
				<p className="small-regular text-muted-foreground text-center mt-4 mb-0!">
					Nothing goes live until you apply.
				</p>
			)}

			<ConfirmDialog
				open={confirmingDismiss}
				onOpenChange={(open) => {
					if (!pending && !open) cancelDismiss();
				}}
				title="Discard this suggestion?"
				description="Your pages keep their current titles, and I won't suggest this again."
				confirmLabel="Yes, discard"
				cancelLabel="Cancel"
				pending={pending === 'secondary'}
				onConfirm={confirmDismiss}
			/>
		</div>
	);
};

export default DupeTitle;
