import { useState, useMemo, useRef, useEffect } from "react";
import { createFileRoute, Link } from "@tanstack/react-router";
import { Plus, Trash2, ReceiptText } from "lucide-react";
import { Button, Input, Combobox, buttonVariants } from "#/components/ui";
import {
	useListBills,
	useCreateBill,
	useSearchCustomers,
	useCreateCustomer,
	useListProducts,
	useListStockBatches,
	trpc,
} from "shared-react";

export const Route = createFileRoute("/billing/")({
	component: BillingPage,
	staticData: {
		title: "Billing",
		subtitle: "Invoice generation & payment management",
	},
});

interface BillItemForm {
	product_id: number;
	product_name: string;
	brand: string;
	batch_id: number | null;
	packs: number;
	loose: number;
	qty: number;
	original_price: number;
	selling_price: number;
	total: number;
	batchOptions: { id: number; batch_no: string; quantity: number; is_default: boolean }[];
}

function BillingPage() {
	const [tab, setTab] = useState<"new" | "history">("new");
	const [customerMobile, setCustomerMobile] = useState("");
	const [customerName, setCustomerName] = useState("");
	const [customerSearch, setCustomerSearch] = useState("");
	const [showCustomerDropdown, setShowCustomerDropdown] = useState(false);
	const [items, setItems] = useState<BillItemForm[]>([]);

	const { data: bills, isLoading: billsLoading } = useListBills();
	const { data: customerResults } = useSearchCustomers(customerSearch);
	const { data: products } = useListProducts();
	const { data: batches } = useListStockBatches();
	const createBillMutation = useCreateBill();
	const createCustomerMutation = useCreateCustomer();
	const utils = trpc.useUtils();

	const custRef = useRef<HTMLDivElement>(null);

	useEffect(() => {
		function handleClickOutside(e: MouseEvent) {
			if (custRef.current && !custRef.current.contains(e.target as Node)) {
				setShowCustomerDropdown(false);
			}
		}
		document.addEventListener("mousedown", handleClickOutside);
		return () => document.removeEventListener("mousedown", handleClickOutside);
	}, []);

	const customerSearchResults = useMemo(() => {
		if (!customerSearch) return [];
		return (customerResults ?? []).filter(
			(c) => c.mobile.includes(customerSearch) || (c.name || "").toLowerCase().includes(customerSearch.toLowerCase()),
		);
	}, [customerSearch, customerResults]);

	function selectCustomer(c: { mobile: string; name: string | null }) {
		setCustomerMobile(c.mobile);
		setCustomerName(c.name || "");
		setShowCustomerDropdown(false);
		setCustomerSearch("");
	}

	function selectAnonymous() {
		setCustomerMobile("Anonymous");
		setCustomerName("");
		setShowCustomerDropdown(false);
		setCustomerSearch("");
	}

	function addCustomer() {
		const mobile = customerSearch.trim();
		if (!mobile) return;
		createCustomerMutation.mutate(
			{ mobile, name: null, added_on: new Date().toISOString().slice(0, 10) },
			{
				onSuccess: (c) => {
					setCustomerMobile(c.mobile);
					setCustomerName(c.name || "");
					setShowCustomerDropdown(false);
					setCustomerSearch("");
				},
			},
		);
	}

	function addItem(product?: (typeof products)[number]) {
		if (product) {
			const productBatches = (batches ?? []).filter((b) => b.product.id === product.id);
			const defaultBatch = productBatches.find((b) => b.is_default);
			setItems((prev) => [
				...prev,
				{
					product_id: product.id,
					product_name: product.name,
					brand: product.brand,
					batch_id: defaultBatch?.id ?? null,
				packs: 1,
				loose: 0,
				qty: product.loose_sale_allowed ? (product.units_per_pack ?? 1) : 1,
				original_price: product.selling_price,
				selling_price: product.selling_price,
				total: product.selling_price,
					batchOptions: productBatches.map((b) => ({
						id: b.id,
						batch_no: b.batch_no,
						quantity: b.quantity,
						is_default: b.is_default,
					})),
				},
			]);
		} else {
			setItems((prev) => [
				...prev,
				{
					product_id: 0,
					product_name: "",
					brand: "",
					batch_id: null,
					packs: 0,
					loose: 0,
					qty: 0,
					original_price: 0,
					selling_price: 0,
					total: 0,
					batchOptions: [],
				},
			]);
		}
	}

	function removeItem(idx: number) {
		setItems((prev) => prev.filter((_, i) => i !== idx));
	}

	function updateItem(idx: number, field: keyof BillItemForm, value: string | number | null) {
		setItems((prev) =>
			prev.map((item, i) => {
				if (i !== idx) return item;

			let updated = { ...item, [field]: value };
			const product = products?.find((p) => p.id === item.product_id);
			const ups = product?.units_per_pack ?? 0;
			const looseAllowed = product?.loose_sale_allowed ?? false;

			const isQuantityField = field === "batch_id" || field === "selling_price" || field === "packs" || field === "loose";

			if (isQuantityField) {
				if (field === "batch_id") {
					const batch = item.batchOptions.find((b) => b.id === Number(value));
					if (!batch) return updated;
				}

				if (looseAllowed) {
					updated.qty = Number(updated.packs) * ups + Number(updated.loose);
					updated.total = Number(updated.packs) * Number(updated.selling_price) + Number(updated.loose) * (Number(updated.selling_price) / ups);
				} else {
					updated.qty = Number(updated.packs);
					updated.total = Number(updated.packs) * Number(updated.selling_price);
				}
			}

				return updated;
			}),
		);
	}

	function applyProductSearch(idx: number, product: (typeof products)[number]) {
		const productBatches = (batches ?? []).filter((b) => b.product.id === product.id);
		const defaultBatch = productBatches.find((b) => b.is_default);
		setItems((prev) =>
			prev.map((item, i) => {
				if (i !== idx) return item;
		const packs = 1;
		const loose = 0;
		const ups = product.units_per_pack ?? 0;
		const qty = product.loose_sale_allowed ? ups : 1;
		return {
			...item,
			product_id: product.id,
			product_name: product.name,
			brand: product.brand,
			batch_id: defaultBatch?.id ?? null,
			packs,
			loose,
			qty,
			original_price: product.selling_price,
			selling_price: product.selling_price,
			total: product.loose_sale_allowed ? ups * product.selling_price : product.selling_price,
					batchOptions: productBatches.map((b) => ({
						id: b.id,
						batch_no: b.batch_no,
						quantity: b.quantity,
						is_default: b.is_default,
					})),
				};
			}),
		);
	}

	const subtotal = items.reduce((s, i) => s + i.total, 0);
	const total = subtotal;

	function handleGenerateBill() {
		if (!customerMobile) return;
		const validItems = items.filter((i) => i.product_id > 0 && i.qty > 0);
		if (validItems.length === 0) return;

		createBillMutation.mutate(
			{
				bill_no: "BIL-" + Date.now().toString(36).toUpperCase(),
				customer_mobile: customerMobile,
				customer_name: customerName || null,
				subtotal,
				tax: 0,
				tax_rate: 0,
				total,
				discount: 0,
				discount_percent: 0,
				created_at: new Date().toISOString(),
				items: validItems.map((i) => ({
					product_id: i.product_id,
					product_name: i.product_name,
					brand: i.brand || null,
					batch_id: i.batch_id,
					packs: i.packs,
					loose: i.loose,
					qty: i.qty,
					original_price: i.original_price,
					selling_price: i.selling_price,
					total: i.total,
				})),
			},
			{
				onSuccess: () => {
					utils.billing.list.invalidate();
					setCustomerMobile("");
					setCustomerName("");
					setItems([]);
					setTab("history");
				},
			},
		);
	}

	return (
		<div>
			<div className="flex gap-0 mb-0 border-b border-slate-200 sticky top-0 bg-white z-20 -mx-6 px-6">
				<button
					type="button"
					onClick={() => setTab("new")}
					className={`px-5 py-3.5 text-sm font-medium border-b-2 transition-colors ${tab === "new" ? "text-blue-600 border-blue-600" : "text-slate-600 border-transparent hover:text-slate-900"}`}
				>
					New Bill
				</button>
				<button
					type="button"
					onClick={() => setTab("history")}
					className={`px-5 py-3.5 text-sm font-medium border-b-2 transition-colors ${tab === "history" ? "text-blue-600 border-blue-600" : "text-slate-600 border-transparent hover:text-slate-900"}`}
				>
					History
				</button>
			</div>

			<div className="pt-6">
				{tab === "new" && (
					<div className="max-w-[960px]">
						{/* Customer */}
						<div className="bg-white rounded-lg shadow-[0_0_0_1px_rgba(0,0,0,0.06),0_1px_2px_rgba(0,0,0,0.04)] p-5 mb-5">
							<h3 className="flex items-center gap-2 text-[13px] font-semibold text-slate-600 uppercase tracking-wider mb-4">
								<ReceiptText className="w-4 h-4" />
								Customer
							</h3>
							<div className="flex items-center gap-2.5">
								<div ref={custRef} className="relative flex-1 max-w-[320px]">
									<Input
										value={customerSearch}
										onChange={(e) => {
											setCustomerSearch(e.target.value);
											setShowCustomerDropdown(true);
										}}
										onFocus={() => setShowCustomerDropdown(true)}
										placeholder="Search by name or mobile..."
									/>
									{showCustomerDropdown && (
										<div className="absolute top-full left-0 right-0 z-30 bg-white border border-slate-200 rounded-md shadow-lg max-h-56 overflow-y-auto mt-1">
											<div
												className="px-3.5 py-2.5 text-sm text-slate-500 italic border-b border-slate-100 cursor-pointer hover:bg-slate-50"
												onClick={selectAnonymous}
											>
												Unknown / Anonymous
											</div>
											{customerSearchResults.map((c) => (
												<div
													key={c.id}
													className="px-3.5 py-2.5 text-sm border-b border-slate-100 cursor-pointer hover:bg-blue-50"
													onClick={() => selectCustomer(c)}
												>
													<span className="font-medium">{c.name || c.mobile}</span>
													{c.name && <span className="text-slate-500 ml-2">{c.mobile}</span>}
												</div>
											))}
											{customerSearch && (
												<div
													className="px-3.5 py-2.5 text-sm text-cyan-600 font-semibold border-t border-slate-200 cursor-pointer hover:bg-cyan-50 flex items-center gap-2"
													onClick={addCustomer}
												>
													<Plus className="w-[18px] h-[18px]" />
													Add New Customer
												</div>
											)}
										</div>
									)}
								</div>
								{customerMobile && (
									<span className="text-sm text-emerald-600 font-medium">
										{customerName || customerMobile}
									</span>
								)}
							</div>
						</div>

						{/* Items */}
						<div className="bg-white rounded-lg shadow-[0_0_0_1px_rgba(0,0,0,0.06),0_1px_2px_rgba(0,0,0,0.04)] p-5 mb-5">
							<h3 className="flex items-center gap-2 text-[13px] font-semibold text-slate-600 uppercase tracking-wider mb-4">
								<ReceiptText className="w-4 h-4" />
								Items
							</h3>
							<div className="overflow-x-auto">
								<table className="w-full text-sm">
									<thead>
										<tr className="text-[11px] font-semibold text-slate-600 uppercase tracking-wider border-b border-slate-200">
											<th className="text-left pb-2 px-2">Product</th>
											<th className="text-left pb-2 px-2">Batch</th>
							<th className="text-center pb-2 px-2 w-[70px]">Packs</th>
							<th className="text-center pb-2 px-2 w-[70px]">Loose</th>
											<th className="text-right pb-2 px-2 w-[110px]">Price</th>
											<th className="text-right pb-2 px-2">Total</th>
											<th className="pb-2 px-2 w-[36px]" />
										</tr>
									</thead>
									<tbody>
										{items.map((item, idx) => (
											<tr key={idx} className="border-b border-slate-100">
												<td className="py-2 px-2 relative" style={{ minWidth: 180 }}>
													{item.product_id > 0 ? (
														<div>
															<div className="font-semibold text-[13px]">{item.product_name}</div>
															<div className="text-xs text-slate-500">{item.brand}</div>
														</div>
													) : (
														<Combobox
															value=""
															onChange={(val) => {
																const product = (products ?? []).find((p) => String(p.id) === val);
																if (product) applyProductSearch(idx, product);
															}}
															options={(products ?? []).map((p) => ({
																value: String(p.id),
																label: `${p.name} — ${p.brand} — ₹${p.selling_price.toFixed(2)}`,
															}))}
															placeholder="Search product..."
															emptyMessage="No products found."
														/>
													)}
												</td>
												<td className="py-2 px-2">
													{item.product_id > 0 && (
														<select
															value={item.batch_id ?? ""}
															onChange={(e) => updateItem(idx, "batch_id", Number(e.target.value) || null)}
															className="w-full px-2 py-1.5 border border-slate-200 rounded text-xs bg-slate-50"
														>
															{item.batchOptions.map((b) => (
																<option key={b.id} value={b.id}>
																	{b.batch_no}{b.is_default ? " ★" : ""} (qty: {b.quantity})
																</option>
															))}
														</select>
													)}
												</td>
											<td className="py-2 px-2">
												<input
													type="number"
													value={item.packs}
													onChange={(e) => updateItem(idx, "packs", Number(e.target.value))}
													className="w-full px-2 py-1.5 border border-slate-200 rounded text-xs text-center"
													min={0}
												/>
											</td>
											<td className="py-2 px-2">
												<input
													type="number"
													value={item.loose}
													onChange={(e) => updateItem(idx, "loose", Number(e.target.value))}
													className="w-full px-2 py-1.5 border border-slate-200 rounded text-xs text-center"
													min={0}
													disabled={!products?.find((p) => p.id === item.product_id)?.loose_sale_allowed}
												/>
											</td>
												<td className="py-2 px-2">
													<input
														type="number"
														value={item.selling_price}
														onChange={(e) => updateItem(idx, "selling_price", Number(e.target.value))}
														className="w-full px-2 py-1.5 border border-slate-200 rounded text-xs text-right"
														min={0}
														step={0.01}
													/>
												</td>
												<td className="py-2 px-2 text-right font-semibold">₹{item.total.toFixed(2)}</td>
												<td className="py-2 px-2 text-center">
													<button type="button" onClick={() => removeItem(idx)} className="w-[30px] h-[30px] flex items-center justify-center rounded text-red-600 hover:bg-red-50">
														<Trash2 className="w-[15px] h-[15px]" />
													</button>
												</td>
											</tr>
										))}
									</tbody>
								</table>
							</div>
							<Button variant="ghost-blue" size="sm" className="mt-3" onClick={() => addItem()}>
								<Plus className="w-3.5 h-3.5" />
								Add Item
							</Button>
						</div>

						{/* Summary */}
						<div className="bg-white rounded-lg shadow-[0_0_0_1px_rgba(0,0,0,0.06),0_1px_2px_rgba(0,0,0,0.04)] p-5">
							<h3 className="flex items-center gap-2 text-[13px] font-semibold text-slate-600 uppercase tracking-wider mb-4">
								Bill Summary
							</h3>
							<div className="max-w-[360px] ml-auto">
								<div className="flex justify-between py-1.5 text-lg font-bold border-t-2 border-slate-900 mt-1.5 pt-2.5">
									<span>Total</span>
									<span className="text-blue-600">₹{total.toFixed(2)}</span>
								</div>
							</div>
							<div className="text-right mt-5">
								<Button
									variant="primary"
									disabled={!customerMobile || items.filter((i) => i.product_id > 0 && i.qty > 0).length === 0 || createBillMutation.isPending}
									onClick={handleGenerateBill}
								>
									{createBillMutation.isPending ? "Generating..." : "Generate Bill"}
								</Button>
							</div>
						</div>
					</div>
				)}

				{tab === "history" && (
					<div>
						{billsLoading && <div className="text-sm text-slate-600 py-8">Loading bills...</div>}
						{(bills ?? []).length === 0 && !billsLoading && (
							<div className="text-center py-16 text-slate-500">
								<ReceiptText className="w-14 h-14 mx-auto mb-4 opacity-30" />
								<h3 className="text-base font-semibold text-slate-900 mb-1.5">No bills yet</h3>
								<p className="text-sm">Generate your first bill to see it here.</p>
							</div>
						)}
						<div className="space-y-3">
							{(bills ?? []).map((bill) => {
								const d = new Date(bill.created_at);
								const dateStr = d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", hour: "2-digit", minute: "2-digit" });
								return (
									<Link
										key={bill.id}
										to="/billing/$id"
										params={{ id: bill.id.toString() }}
										className="flex items-center justify-between gap-4 bg-white rounded-lg shadow-[0_0_0_1px_rgba(0,0,0,0.06),0_1px_2px_rgba(0,0,0,0.04)] p-4 hover:shadow-lg transition-shadow cursor-pointer"
									>
										<div>
											<div className="text-[13px] font-semibold text-blue-600">{bill.bill_no}</div>
											<div className="text-sm mt-1">{bill.customer_name || bill.customer_mobile}</div>
											<div className="text-xs text-slate-500 mt-0.5">{dateStr}</div>
										</div>
										<div className="text-right">
											<div className="text-base font-bold text-emerald-600">₹{bill.total.toFixed(2)}</div>
											<div className="text-xs text-slate-500">{bill.items.length} item{bill.items.length > 1 ? "s" : ""}</div>
											<span className="inline-block mt-1 px-2 py-0.5 rounded-full text-[11px] font-semibold bg-emerald-50 text-emerald-600">Completed</span>
										</div>
									</Link>
								);
							})}
						</div>
					</div>
				)}
			</div>
		</div>
	);
}
