import { useMemo } from "react";
import { useFormatters } from "../hooks/useFormatters";
import type { CandidateDelta } from "../hooks/useImpactDeltas";
import { LucideIcon } from "../lib/iconData";
import { useUIStore } from "../stores/uiStore";
import { RankBadge } from "./CandidateListItem";
import { GearImage } from "./GearImage";
import { ImpactDeltaBadge } from "./ImpactDeltaBadge";

interface CandidateWithCategory {
	id: number;
	threadId: number;
	name: string;
	weightGrams: number | null;
	priceCents: number | null;
	categoryId: number;
	notes: string | null;
	productUrl: string | null;
	imageFilename: string | null;
	imageUrl?: string | null;
	status: "researching" | "ordered" | "arrived";
	pros: string | null;
	cons: string | null;
	createdAt: string;
	updatedAt: string;
	categoryName: string;
	categoryIcon: string;
}

interface ComparisonTableProps {
	candidates: CandidateWithCategory[];
	resolvedCandidateId: number | null;
	deltas?: Record<number, CandidateDelta>;
}

const STATUS_LABELS: Record<"researching" | "ordered" | "arrived", string> = {
	researching: "Researching",
	ordered: "Ordered",
	arrived: "Arrived",
};

export function ComparisonTable({
	candidates,
	resolvedCandidateId,
	deltas,
}: ComparisonTableProps) {
	const { weight, price } = useFormatters();
	const openExternalLink = useUIStore((s) => s.openExternalLink);

	const { bestWeightId, bestPriceId, weightDeltas, priceDeltas } =
		useMemo(() => {
			// Weight deltas
			const withWeight = candidates.filter((c) => c.weightGrams != null);
			let bestWeightId: number | null = null;
			const weightDeltas: Record<number, string | null> = {};

			if (withWeight.length > 0) {
				const minWeight = Math.min(
					...withWeight.map((c) => c.weightGrams as number),
				);
				bestWeightId =
					withWeight.find((c) => c.weightGrams === minWeight)?.id ?? null;
				for (const c of candidates) {
					if (c.weightGrams == null) {
						weightDeltas[c.id] = null;
					} else {
						const delta = c.weightGrams - minWeight;
						weightDeltas[c.id] = delta === 0 ? null : `+${weight(delta)}`;
					}
				}
			} else {
				for (const c of candidates) {
					weightDeltas[c.id] = null;
				}
			}

			// Price deltas
			const withPrice = candidates.filter((c) => c.priceCents != null);
			let bestPriceId: number | null = null;
			const priceDeltas: Record<number, string | null> = {};

			if (withPrice.length > 0) {
				const minPrice = Math.min(
					...withPrice.map((c) => c.priceCents as number),
				);
				bestPriceId =
					withPrice.find((c) => c.priceCents === minPrice)?.id ?? null;
				for (const c of candidates) {
					if (c.priceCents == null) {
						priceDeltas[c.id] = null;
					} else {
						const delta = c.priceCents - minPrice;
						priceDeltas[c.id] = delta === 0 ? null : `+${price(delta)}`;
					}
				}
			} else {
				for (const c of candidates) {
					priceDeltas[c.id] = null;
				}
			}

			return { bestWeightId, bestPriceId, weightDeltas, priceDeltas };
		}, [candidates, weight, price]);

	const ATTRIBUTE_ROWS: Array<{
		key: string;
		label: string;
		render: (
			candidate: CandidateWithCategory,
			index: number,
		) => React.ReactNode;
		cellClass?: (candidate: CandidateWithCategory) => string;
	}> = [
		{
			key: "image",
			label: "Image",
			render: (c) => (
				<div
					className="w-12 h-12 rounded-lg overflow-hidden flex items-center justify-center"
					style={{
						backgroundColor: c.imageUrl
							? ((c as Record<string, unknown>).dominantColor as string) ||
								"#f3f4f6"
							: undefined,
					}}
				>
					{c.imageUrl ? (
						<GearImage src={c.imageUrl} alt={c.name} />
					) : (
						<LucideIcon
							name={c.categoryIcon}
							size={20}
							className="text-gray-400"
						/>
					)}
				</div>
			),
		},
		{
			key: "name",
			label: "Name",
			render: (c) => (
				<span className="text-sm font-medium text-gray-900">{c.name}</span>
			),
		},
		{
			key: "rank",
			label: "Rank",
			render: (_c, index) => <RankBadge rank={index + 1} />,
		},
		{
			key: "weight",
			label: "Weight",
			render: (c) => {
				const isBest = c.id === bestWeightId;
				const delta = weightDeltas[c.id];
				if (c.weightGrams == null) {
					return <span className="text-gray-300">—</span>;
				}
				return (
					<div>
						<span className="font-medium text-gray-900">
							{weight(c.weightGrams)}
						</span>
						{!isBest && delta && (
							<div className="text-xs text-gray-400">{delta}</div>
						)}
					</div>
				);
			},
			cellClass: (c) => {
				if (c.id === bestWeightId) return "bg-blue-50";
				if (c.id === resolvedCandidateId) return "bg-amber-50/50";
				return "";
			},
		},
		{
			key: "price",
			label: "Price",
			render: (c) => {
				const isBest = c.id === bestPriceId;
				const delta = priceDeltas[c.id];
				if (c.priceCents == null) {
					return <span className="text-gray-300">—</span>;
				}
				return (
					<div>
						<span className="font-medium text-gray-900">
							{price(c.priceCents)}
						</span>
						{!isBest && delta && (
							<div className="text-xs text-gray-400">{delta}</div>
						)}
					</div>
				);
			},
			cellClass: (c) => {
				if (c.id === bestPriceId) return "bg-green-50";
				if (c.id === resolvedCandidateId) return "bg-amber-50/50";
				return "";
			},
		},
		{
			key: "status",
			label: "Status",
			render: (c) => (
				<span className="text-xs text-gray-600">{STATUS_LABELS[c.status]}</span>
			),
		},
		{
			key: "link",
			label: "Link",
			render: (c) =>
				c.productUrl ? (
					<button
						type="button"
						onClick={() => openExternalLink(c.productUrl as string)}
						className="text-xs text-blue-500 hover:underline"
					>
						View
					</button>
				) : (
					<span className="text-gray-300">—</span>
				),
		},
		{
			key: "notes",
			label: "Notes",
			render: (c) =>
				c.notes ? (
					<p className="text-xs text-gray-700 whitespace-pre-line">{c.notes}</p>
				) : (
					<span className="text-gray-300">—</span>
				),
		},
		{
			key: "pros",
			label: "Pros",
			render: (c) => {
				if (!c.pros) return <span className="text-gray-300">—</span>;
				const items = c.pros.split("\n").filter((s) => s.trim() !== "");
				if (items.length === 0) return <span className="text-gray-300">—</span>;
				return (
					<ul className="list-disc list-inside space-y-0.5">
						{items.map((item, i) => (
							// biome-ignore lint/suspicious/noArrayIndexKey: stable list of static items
							<li key={i} className="text-xs text-gray-700">
								{item}
							</li>
						))}
					</ul>
				);
			},
		},
		{
			key: "cons",
			label: "Cons",
			render: (c) => {
				if (!c.cons) return <span className="text-gray-300">—</span>;
				const items = c.cons.split("\n").filter((s) => s.trim() !== "");
				if (items.length === 0) return <span className="text-gray-300">—</span>;
				return (
					<ul className="list-disc list-inside space-y-0.5">
						{items.map((item, i) => (
							// biome-ignore lint/suspicious/noArrayIndexKey: stable list of static items
							<li key={i} className="text-xs text-gray-700">
								{item}
							</li>
						))}
					</ul>
				);
			},
		},
	];

	// Determine if impact rows should be shown
	const firstDelta = deltas ? Object.values(deltas)[0] : undefined;
	const showImpact = !!deltas && !!firstDelta && firstDelta.mode !== "none";

	const tableMinWidth = Math.max(400, candidates.length * 180);

	return (
		<div className="overflow-x-auto rounded-xl border border-gray-100">
			<table
				className="border-collapse text-sm w-full"
				style={{ minWidth: `${tableMinWidth}px` }}
			>
				<thead>
					<tr className="border-b border-gray-100">
						{/* Sticky empty corner cell */}
						<th className="sticky left-0 z-10 bg-white px-4 py-3 text-left text-xs font-medium text-gray-700 w-28" />
						{candidates.map((candidate) => {
							const isWinner = candidate.id === resolvedCandidateId;
							return (
								<th
									key={candidate.id}
									className={`px-4 py-3 text-left text-xs font-medium min-w-[160px] ${
										isWinner ? "bg-amber-50 text-amber-800" : "text-gray-700"
									}`}
								>
									<div className="flex items-center gap-1">
										{isWinner && (
											<LucideIcon
												name="trophy"
												size={12}
												className="text-amber-600"
											/>
										)}
										{candidate.name}
									</div>
								</th>
							);
						})}
					</tr>
				</thead>
				<tbody>
					{ATTRIBUTE_ROWS.map((row) => (
						<tr key={row.key} className="border-b border-gray-50">
							{/* Sticky label cell */}
							<td className="sticky left-0 z-10 bg-white px-4 py-3 text-xs font-medium text-gray-500 uppercase tracking-wide w-28">
								{row.label}
							</td>
							{candidates.map((candidate, index) => {
								const isWinner = candidate.id === resolvedCandidateId;
								const extraClass = row.cellClass
									? row.cellClass(candidate)
									: isWinner
										? "bg-amber-50/50"
										: "";
								return (
									<td
										key={candidate.id}
										className={`px-4 py-3 min-w-[160px] ${extraClass}`}
									>
										{row.render(candidate, index)}
									</td>
								);
							})}
						</tr>
					))}
					{showImpact && (
						<>
							<tr className="border-b border-gray-50">
								<td className="sticky left-0 z-10 bg-white px-4 py-3 text-xs font-medium text-gray-500 uppercase tracking-wide w-28">
									Weight Impact
								</td>
								{candidates.map((candidate) => {
									const isWinner = candidate.id === resolvedCandidateId;
									return (
										<td
											key={candidate.id}
											className={`px-4 py-3 min-w-[160px] ${isWinner ? "bg-amber-50/50" : ""}`}
										>
											<ImpactDeltaBadge
												delta={deltas?.[candidate.id]}
												type="weight"
												formatFn={weight}
											/>
										</td>
									);
								})}
							</tr>
							<tr className="border-b border-gray-50">
								<td className="sticky left-0 z-10 bg-white px-4 py-3 text-xs font-medium text-gray-500 uppercase tracking-wide w-28">
									Price Impact
								</td>
								{candidates.map((candidate) => {
									const isWinner = candidate.id === resolvedCandidateId;
									return (
										<td
											key={candidate.id}
											className={`px-4 py-3 min-w-[160px] ${isWinner ? "bg-amber-50/50" : ""}`}
										>
											<ImpactDeltaBadge
												delta={deltas?.[candidate.id]}
												type="price"
												formatFn={price}
											/>
										</td>
									);
								})}
							</tr>
						</>
					)}
				</tbody>
			</table>
		</div>
	);
}
