"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { callAuthEndpoint } from "athena-auth-js";
import { authClient } from "../lib/auth-client";
import { SharedBackButton } from "./shared-back-button";
import { Badge } from "./ui/badge";
import { Button } from "./ui/button";
import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "./ui/card";

type SessionRow = {
	id: string;
	token: string;
	userId: string;
	ipAddress: string | null;
	createdAt: string | null;
	expiresAt: string | null;
};

function normalizeSessionRow(input: unknown): SessionRow | null {
	if (!input || typeof input !== "object") return null;
	const record = input as Record<string, unknown>;
	const id = typeof record.id === "string" ? record.id : null;
	const token = typeof record.token === "string" ? record.token : null;
	const userId =
		typeof record.userId === "string"
			? record.userId
			: typeof record.user_id === "string"
				? record.user_id
				: null;

	if (!id || !token || !userId) return null;

	return {
		id,
		token,
		userId,
		ipAddress:
			typeof record.ipAddress === "string"
				? record.ipAddress
				: typeof record.ip_address === "string"
					? record.ip_address
					: null,
		createdAt:
			typeof record.createdAt === "string"
				? record.createdAt
				: typeof record.created_at === "string"
					? record.created_at
					: null,
		expiresAt:
			typeof record.expiresAt === "string"
				? record.expiresAt
				: typeof record.expires_at === "string"
					? record.expires_at
					: null,
	};
}

function formatDateTime(value: string | null): string {
	if (!value) return "-";
	const parsed = Date.parse(value);
	if (Number.isNaN(parsed)) return value;
	return new Intl.DateTimeFormat("en-GB", {
		year: "numeric",
		month: "short",
		day: "2-digit",
		hour: "2-digit",
		minute: "2-digit",
	}).format(new Date(parsed));
}

function truncateToken(token: string): string {
	if (token.length <= 18) return token;
	return `${token.slice(0, 8)}...${token.slice(-8)}`;
}

export function SessionActivityView() {
	const {
		data: currentSessionData,
		refetch: refetchCurrentSession,
		isPending: sessionPending,
	} = authClient.useSession();
	const currentToken = currentSessionData?.session?.token ?? null;

	const [loading, setLoading] = useState(true);
	const [error, setError] = useState<string | null>(null);
	const [notice, setNotice] = useState<string | null>(null);
	const [sessions, setSessions] = useState<SessionRow[]>([]);
	const [revokePendingToken, setRevokePendingToken] = useState<string | null>(
		null,
	);
	const [revokeOtherPending, setRevokeOtherPending] = useState(false);
	const [revokeAllPending, setRevokeAllPending] = useState(false);

	const loadSessions = useCallback(async () => {
		setLoading(true);
		setError(null);
		const result = await callAuthEndpoint<unknown[]>("/list-sessions", {
			method: "GET",
		});

		if (!result.ok) {
			setError(result.message || "Failed to load sessions");
			setSessions([]);
			setLoading(false);
			return;
		}

		const rows = (Array.isArray(result.body) ? result.body : [])
			.map(normalizeSessionRow)
			.filter((row): row is SessionRow => row !== null)
			.sort((left, right) => {
				const leftTime = left.createdAt ? Date.parse(left.createdAt) : 0;
				const rightTime = right.createdAt ? Date.parse(right.createdAt) : 0;
				return rightTime - leftTime;
			});

		setSessions(rows);
		setLoading(false);
	}, []);

	const refreshAll = async () => {
		await Promise.all([loadSessions(), refetchCurrentSession()]);
	};

	const revokeSession = async (token: string) => {
		setRevokePendingToken(token);
		setError(null);
		setNotice(null);

		const result = await callAuthEndpoint<{ status?: boolean }>(
			"/revoke-session",
			{
				method: "POST",
				body: JSON.stringify({ token }),
			},
		);

		if (!result.ok) {
			setError(result.message || "Failed to revoke session");
			setRevokePendingToken(null);
			return;
		}

		await refreshAll();
		setNotice("Session revoked.");
		setRevokePendingToken(null);
	};

	const revokeOtherSessions = async () => {
		setRevokeOtherPending(true);
		setError(null);
		setNotice(null);
		const result = await callAuthEndpoint<{ status?: boolean }>(
			"/revoke-other-sessions",
			{ method: "POST" },
		);

		if (!result.ok) {
			setError(result.message || "Failed to revoke other sessions");
			setRevokeOtherPending(false);
			return;
		}

		await refreshAll();
		setNotice("All other sessions revoked.");
		setRevokeOtherPending(false);
	};

	const revokeAllSessions = async () => {
		const shouldProceed = window.confirm(
			"Revoke all sessions for this user? This can sign out the current browser session.",
		);
		if (!shouldProceed) return;

		setRevokeAllPending(true);
		setError(null);
		setNotice(null);
		const result = await callAuthEndpoint<{ status?: boolean }>(
			"/revoke-sessions",
			{
				method: "POST",
				body: JSON.stringify({}),
			},
		);

		if (!result.ok) {
			setError(result.message || "Failed to revoke all sessions");
			setRevokeAllPending(false);
			return;
		}

		await refreshAll();
		setNotice("All sessions revoked.");
		setRevokeAllPending(false);
	};

	useEffect(() => {
		void loadSessions();
		const onVisible = () => {
			if (!document.hidden) {
				void loadSessions();
			}
		};
		const interval = window.setInterval(() => {
			void loadSessions();
		}, 30000);
		document.addEventListener("visibilitychange", onVisible);
		return () => {
			window.clearInterval(interval);
			document.removeEventListener("visibilitychange", onVisible);
		};
	}, [loadSessions]);

	const currentSession = useMemo(
		() =>
			currentToken
				? (sessions.find((session) => session.token === currentToken) ?? null)
				: null,
		[sessions, currentToken],
	);
	const currentSessionId = currentSession?.id ?? null;
	const otherSessionsCount = sessions.filter(
		(session) => session.id !== currentSessionId,
	).length;

	return (
		<main className="mx-auto w-full max-w-7xl px-4 pb-10 pt-8">
			<div className="mb-4 flex flex-wrap items-center justify-between gap-3">
				<SharedBackButton fallbackHref="/session" />
				<div className="flex flex-wrap items-center gap-2 text-xs">
					<Badge
						variant={
							loading || sessionPending
								? "secondary"
								: error
									? "destructive"
									: "success"
						}
					>
						{loading || sessionPending ? "loading" : error ? "error" : "ready"}
					</Badge>
					<Badge variant="secondary">sessions: {sessions.length}</Badge>
					<Badge variant="secondary">
						other sessions: {otherSessionsCount}
					</Badge>
					<Badge variant="secondary">auto refresh: 30s + focus</Badge>
				</div>
			</div>

			<Card>
				<CardHeader>
					<CardTitle>Session Activity</CardTitle>
					<CardDescription>
						Manage every active session with precise revoke controls.
					</CardDescription>
				</CardHeader>
				<CardContent className="grid gap-4">
					{error ? (
						<p className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
							{error}
						</p>
					) : null}
					{notice ? (
						<p className="rounded-md border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-700">
							{notice}
						</p>
					) : null}

					<section className="grid gap-3 rounded-xl border border-slate-200 bg-white p-4 md:grid-cols-3">
						<div className="rounded-lg border border-slate-200 bg-slate-50 p-3">
							<div className="text-xs uppercase tracking-wide text-slate-500">
								Current session
							</div>
							<div className="mt-1 text-sm font-medium">
								{currentSession
									? currentSession.ipAddress || "Unknown location"
									: "Not resolved"}
							</div>
							<div className="mt-1 text-xs text-slate-600">
								Expires: {formatDateTime(currentSession?.expiresAt ?? null)}
							</div>
						</div>
						<div className="rounded-lg border border-slate-200 bg-slate-50 p-3">
							<div className="text-xs uppercase tracking-wide text-slate-500">
								Current token
							</div>
							<div className="mt-1 text-sm font-medium">
								{currentToken ? truncateToken(currentToken) : "none"}
							</div>
							<div className="mt-1 text-xs text-slate-600">
								Session id: {currentSession?.id ?? "-"}
							</div>
						</div>
						<div className="rounded-lg border border-slate-200 bg-slate-50 p-3">
							<div className="text-xs uppercase tracking-wide text-slate-500">
								Bulk actions
							</div>
							<div className="mt-2 flex flex-wrap gap-2">
								<Button
									type="button"
									size="sm"
									variant="secondary"
									disabled={revokeOtherPending || revokeAllPending}
									onClick={() => void revokeOtherSessions()}
								>
									{revokeOtherPending ? "Revoking..." : "Revoke others"}
								</Button>
								<Button
									type="button"
									size="sm"
									variant="destructive"
									disabled={revokeOtherPending || revokeAllPending}
									onClick={() => void revokeAllSessions()}
								>
									{revokeAllPending ? "Revoking..." : "Revoke all"}
								</Button>
							</div>
						</div>
					</section>

					<div className="overflow-auto rounded-xl border border-slate-200 bg-white">
						<table className="min-w-full table-fixed text-sm">
							<thead>
								<tr className="border-b border-slate-200 text-left text-slate-600">
									<th className="px-4 py-3 font-medium">Session ID</th>
									<th className="px-4 py-3 font-medium">Token</th>
									<th className="px-4 py-3 font-medium">IP</th>
									<th className="px-4 py-3 font-medium">Created</th>
									<th className="px-4 py-3 font-medium">Expires</th>
									<th className="px-4 py-3 font-medium">State</th>
									<th className="px-4 py-3 text-right font-medium">Actions</th>
								</tr>
							</thead>
							<tbody>
								{sessions.length > 0 ? (
									sessions.map((session) => {
										const isCurrent = currentToken === session.token;
										return (
											<tr
												key={session.id}
												className="border-b border-slate-100 last:border-b-0"
											>
												<td className="max-w-[170px] truncate px-4 py-3">
													{session.id}
												</td>
												<td className="max-w-[160px] truncate px-4 py-3">
													{truncateToken(session.token)}
												</td>
												<td className="px-4 py-3">
													{session.ipAddress || "-"}
												</td>
												<td className="px-4 py-3">
													{formatDateTime(session.createdAt)}
												</td>
												<td className="px-4 py-3">
													{formatDateTime(session.expiresAt)}
												</td>
												<td className="px-4 py-3">
													<Badge variant={isCurrent ? "success" : "secondary"}>
														{isCurrent ? "current" : "other"}
													</Badge>
												</td>
												<td className="px-4 py-3 text-right">
													<Button
														type="button"
														size="sm"
														variant="outline"
														disabled={
															isCurrent || revokePendingToken === session.token
														}
														onClick={() => void revokeSession(session.token)}
													>
														{revokePendingToken === session.token
															? "Revoking..."
															: "Revoke"}
													</Button>
												</td>
											</tr>
										);
									})
								) : (
									<tr>
										<td
											colSpan={7}
											className="px-4 py-6 text-center text-slate-500"
										>
											No active sessions found.
										</td>
									</tr>
								)}
							</tbody>
						</table>
					</div>
				</CardContent>
			</Card>
		</main>
	);
}
