import { useMutation, useQuery } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import {
	createColumnHelper,
	flexRender,
	getCoreRowModel,
	getPaginationRowModel,
	getSortedRowModel,
	type SortingState,
	useReactTable,
} from "@tanstack/react-table";
import axios from "axios";
import { ArrowDown, ArrowUp } from "lucide-react";
import React, { useEffect, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Skeleton } from "@/components/ui/skeleton";
import {
	Table,
	TableBody,
	TableCell,
	TableHead,
	TableHeader,
	TableRow,
} from "@/components/ui/table";
import { getServers } from "@/lib/querys/admin/getServers";
import { getServerStats } from "@/lib/querys/serverStats";

type ServerData = {
	name: string;
	serverDNS: string;
	plantToken: string;
	ipAddress: string;
	uptime: string;
	build: string;
	pendingUpdateFile: string;
	lastUpdate: Date;
	memoryUsage: string;
	greatPlainsPlantCode: string;
};

const updateServerItem = async (
	token: string,
	data: Record<string, string | number | boolean | null>,
) => {
	try {
		const res = axios.patch(`/lst/api/admin/server/${token}`, data, {
			withCredentials: true,
		});

		toast.success(`Updated: ${data.field} set to ${data.value}`);
		return res;
	} catch (err) {
		toast.error(`Error updating: ${data.field} being set to ${data.value}`);
		return err;
	}
};
export const Route = createFileRoute("/_app/_adminLayout/admin/servers")({
	component: RouteComponent,
});

function RouteComponent() {
	const { data, isLoading, refetch } = useQuery(getServers());
	const { data: stats = [], isLoading: loadingStats } = useQuery(
		getServerStats(),
	);
	const [sorting, setSorting] = useState<SortingState>([]);
	const columnHelper = createColumnHelper<ServerData>();
	const [pagination, setPagination] = useState({
		pageIndex: 0, //initial page index
		pageSize: 20, //default page size
	});

	const statsMap = React.useMemo(() => {
		const map = new Map<string, any>();
		stats.forEach((stat: any) => map.set(stat.plantToken, stat));
		return map;
	}, [stats]);

	const updateServer = useMutation({
		mutationFn: ({
			token,
			field,
			value,
		}: {
			token: string;
			field: string;
			value: string | number | boolean | null;
		}) => updateServerItem(token, { [field]: value }),

		onSuccess: () => {
			// refetch or update cache

			refetch();
		},
	});

	const columns = [
		columnHelper.accessor("name", {
			cell: ({ row, getValue }) => {
				let url = "";
				if (row.original.plantToken.includes("test")) {
					url = `https://${row.original.serverDNS}.alpla.net/lst/app`;
				} else {
					url = `https://${row.original.plantToken}prod.alpla.net/lst/app`;
				}

				return (
					<a href={url} target="_blank">
						{getValue()}
					</a>
				);
			},
			header: ({ column }) => {
				return (
					<Button
						variant="ghost"
						onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
					>
						<span className="flex flex-row gap-2">Name</span>
						{column.getIsSorted() === "asc" ? (
							<ArrowUp className="ml-2 h-4 w-4" />
						) : (
							<ArrowDown className="ml-2 h-4 w-4" />
						)}
					</Button>
				);
			},
		}),

		columnHelper.accessor("serverDNS", {
			header: ({ column }) => {
				return (
					<Button
						variant="ghost"
						onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
					>
						<span className="flex flex-row gap-2">Server</span>
						{column.getIsSorted() === "asc" ? (
							<ArrowUp className="ml-2 h-4 w-4" />
						) : (
							<ArrowDown className="ml-2 h-4 w-4" />
						)}
					</Button>
				);
			},
			cell: ({ row, getValue }) => {
				const initialValue = String(getValue() ?? "");
				const [localValue, setLocalValue] = React.useState(initialValue);
				const token = row.original.plantToken;
				const field = "serverDNS";

				useEffect(() => setLocalValue(initialValue), [initialValue]);

				const handleSubmit = (newValue: string) => {
					if (newValue !== initialValue) {
						setLocalValue(newValue); // keep new value locally immediately
						updateServer.mutate({ token, field, value: newValue });
					}
				};

				let submitting = false;
				return (
					<Input
						value={localValue}
						onChange={(e) => setLocalValue(e.currentTarget.value)}
						onBlur={(e) => {
							if (!submitting) {
								submitting = true;
								handleSubmit(e.currentTarget.value.trim());
								setTimeout(() => (submitting = false), 100); // reset after slight delay
							}
						}}
						onKeyDown={(e) => {
							if (e.key === "Enter") {
								e.preventDefault();
								handleSubmit(e.currentTarget.value.trim());
								e.currentTarget.blur(); // exit edit mode
								setTimeout(() => (submitting = false), 100);
							}
						}}
					/>
				);
			},
		}),
		columnHelper.accessor("ipAddress", {
			header: ({ column }) => {
				return (
					<Button
						variant="ghost"
						onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
					>
						<span className="flex flex-row gap-2">IP Address</span>
						{column.getIsSorted() === "asc" ? (
							<ArrowUp className="ml-2 h-4 w-4" />
						) : (
							<ArrowDown className="ml-2 h-4 w-4" />
						)}
					</Button>
				);
			},
			cell: ({ row, getValue }) => {
				const initialValue = String(getValue() ?? "");
				const [localValue, setLocalValue] = React.useState(initialValue);
				const token = row.original.plantToken;
				const field = "ipAddress";

				useEffect(() => setLocalValue(initialValue), [initialValue]);

				const handleSubmit = (newValue: string) => {
					if (newValue !== initialValue) {
						setLocalValue(newValue); // keep new value locally immediately
						updateServer.mutate({ token, field, value: newValue });
					}
				};
				return (
					<Input
						value={localValue}
						onChange={(e) => setLocalValue(e.currentTarget.value)}
						onBlur={(e) => handleSubmit(e.currentTarget.value.trim())}
						onKeyDown={(e) => {
							if (e.key === "Enter") {
								e.preventDefault();
								handleSubmit(e.currentTarget.value.trim());
								e.currentTarget.blur(); // exit edit mode
							}
						}}
					/>
				);
			},
		}),

		columnHelper.accessor("greatPlainsPlantCode", {
			header: () => {
				return <span className="flex flex-row gap-2">GP Code</span>;
			},
			cell: ({ row, getValue }) => {
				const initialValue = String(getValue() ?? "");
				const [localValue, setLocalValue] = React.useState(initialValue);
				const token = row.original.plantToken;
				const field = "greatPlainsPlantCode";

				useEffect(() => setLocalValue(initialValue), [initialValue]);

				const handleSubmit = (newValue: string) => {
					if (newValue !== initialValue) {
						setLocalValue(newValue); // keep new value locally immediately
						updateServer.mutate({ token, field, value: newValue });
					}
				};
				return (
					<Input
						value={localValue}
						onChange={(e) => setLocalValue(e.currentTarget.value)}
						onBlur={(e) => handleSubmit(e.currentTarget.value.trim())}
						onKeyDown={(e) => {
							if (e.key === "Enter") {
								e.preventDefault();
								handleSubmit(e.currentTarget.value.trim());
								e.currentTarget.blur(); // exit edit mode
							}
						}}
					/>
				);
			},
		}),

		columnHelper.accessor("uptime", {
			header: () => {
				return <span className="flex flex-row gap-2">UpTime</span>;
			},
			cell: ({ row }) => {
				const statsRow = statsMap.get(row.original.plantToken);

				if (loadingStats) {
					// use Skeleton from shadcn/ui (or any placeholder)
					return <Skeleton className="h-4 w-16" />;
				}
				//console.log(statsMap);
				return (
					<span>
						{statsRow ? `${statsRow.uptime.toFixed(2)}` : "Server Offline?"}
					</span>
				);
			},
		}),
		columnHelper.accessor("lastUpdate", {
			header: () => {
				return <span className="flex flex-row gap-2">Last Updated</span>;
			},
			cell: ({ row }) => {
				const statsRow = statsMap.get(row.original.plantToken);

				if (loadingStats) {
					// use Skeleton from shadcn/ui (or any placeholder)
					return <Skeleton className="h-4 w-16" />;
				}
				//console.log(statsMap);
				return (
					<span>{statsRow ? `${statsRow.lastUpdate}` : "Server Offline?"}</span>
				);
			},
		}),
		columnHelper.accessor("build", {
			header: () => {
				return <span className="flex flex-row gap-2">Build Number</span>;
			},
			cell: ({ row }) => {
				const statsRow = statsMap.get(row.original.plantToken);

				if (loadingStats) {
					// use Skeleton from shadcn/ui (or any placeholder)
					return <Skeleton className="h-4 w-16" />;
				}
				//console.log(statsMap);
				return (
					<span>{statsRow ? `${statsRow.build}` : "Server Offline?"}</span>
				);
			},
		}),
		columnHelper.accessor("pendingUpdateFile", {
			header: () => {
				return <span className="flex flex-row gap-2">Pending Update</span>;
			},
			cell: ({ row }) => {
				const statsRow = statsMap.get(row.original.plantToken);

				if (loadingStats) {
					// use Skeleton from shadcn/ui (or any placeholder)
					return <Skeleton className="h-4 w-16" />;
				}
				//console.log(statsMap);
				return (
					<span>
						{statsRow
							? `${statsRow.pendingUpdateFile === null ? "nothing pending" : statsRow.pendingUpdateFile}`
							: "Server Offline?"}
					</span>
				);
			},
		}),
		columnHelper.accessor("memoryUsage", {
			header: () => {
				return <span className="flex flex-row gap-2">Memory Usage</span>;
			},
			cell: ({ row }) => {
				const statsRow = statsMap.get(row.original.plantToken);

				if (loadingStats) {
					// use Skeleton from shadcn/ui (or any placeholder)
					return <Skeleton className="h-4 w-16" />;
				}
				//console.log(statsMap);
				return (
					<span>
						{statsRow ? `${statsRow.memoryUsage}` : "Server Offline?"}
					</span>
				);
			},
		}),
	];

	const table = useReactTable({
		data,
		columns,
		getCoreRowModel: getCoreRowModel(),
		getPaginationRowModel: getPaginationRowModel(),
		onSortingChange: setSorting,
		getSortedRowModel: getSortedRowModel(),
		onPaginationChange: setPagination,
		//renderSubComponent: ({ row }: { row: any }) => <ExpandedRow row={row} />,
		//getRowCanExpand: () => true,
		state: {
			sorting,
			pagination,
		},
	});

	if (isLoading) {
		return <div className="m-auto">Loading user data</div>;
	}
	return (
		<div className="p-4">
			<div className="w-fit">
				<Table>
					<TableHeader>
						{table.getHeaderGroups().map((headerGroup) => (
							<TableRow key={headerGroup.id}>
								{headerGroup.headers.map((header) => {
									return (
										<TableHead key={header.id}>
											{header.isPlaceholder
												? null
												: flexRender(
														header.column.columnDef.header,
														header.getContext(),
													)}
										</TableHead>
									);
								})}
							</TableRow>
						))}
					</TableHeader>
					<TableBody>
						{table.getRowModel().rows.map((row) => (
							<React.Fragment key={row.id}>
								<TableRow
									key={row.id}
									data-state={row.getIsSelected() && "selected"}
								>
									{row.getVisibleCells().map((cell) => (
										<TableCell key={cell.id}>
											{flexRender(
												cell.column.columnDef.cell,
												cell.getContext(),
											)}
										</TableCell>
									))}
								</TableRow>

								{/* {row.getIsExpanded() && (
									<TableRow>
										<TableCell colSpan={row.getVisibleCells().length}>
											{renderSubComponent({ row })}
										</TableCell>
									</TableRow>
								)} */}
							</React.Fragment>
						))}
					</TableBody>
				</Table>
				<div className="flex items-center justify-end space-x-2 py-4">
					<Button
						variant="outline"
						size="sm"
						onClick={() => table.previousPage()}
						disabled={!table.getCanPreviousPage()}
					>
						Previous
					</Button>
					<Button
						variant="outline"
						size="sm"
						onClick={() => table.nextPage()}
						disabled={!table.getCanNextPage()}
					>
						Next
					</Button>
				</div>
			</div>
		</div>
	);
}
