"use client";

import { useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { ExternalLink, Globe, HelpCircle, LogIn, LogOut, Monitor, ShieldAlert, Smartphone, Tablet, TerminalSquare, Users } from "lucide-react";
import { PageHeader } from "@/components/shared/page-header";
import { StatCard } from "@/components/shared/stat-card";
import { StatusRail, type RailTone } from "@/components/shared/status-rail";
import { ConfirmDialog } from "@/components/shared/confirm-dialog";
import { DebouncedSearch } from "@/components/shared/debounced-search";
import { Pagination } from "@/components/shared/pagination";
import { EmptyState, ErrorState, TableSkeleton } from "@/components/shared/states";
import { Badge, StatusBadge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { useCan } from "@/features/auth/use-can";
import { useI18n, useT } from "@/i18n";
import { friendlyErrorMessage } from "@/lib/errors";
import { formatDateTime, formatNumber, formatRelative } from "@/lib/format";
import { queryKeys } from "@/lib/query-keys";
import { useUrlState } from "@/lib/use-url-state";
import { closeLoginSession, getLoginHistory, getLoginHistoryStats } from "@/services/login-history";
import type { LoginDeviceType, LoginGuardValue, LoginHistoryEntry, LoginStatusValue } from "@/types/login-history";

const GUARDS: LoginGuardValue[] = ["admin", "driver", "store_portal"];
const STATUSES: LoginStatusValue[] = ["success", "failed", "blocked"];

const DEVICE_ICON: Record<LoginDeviceType, React.ComponentType<{ className?: string }>> = {
  desktop: Monitor,
  mobile: Smartphone,
  tablet: Tablet,
  app: TerminalSquare,
  unknown: HelpCircle,
};

const STATUS_VARIANT = { success: "success", failed: "destructive", blocked: "warning" } as const;
const STATUS_RAIL: Record<LoginStatusValue, RailTone> = { success: "done", failed: "problem", blocked: "waiting" };

function deviceLine(entry: LoginHistoryEntry): string {
  const { browser, browser_version, os, os_version } = entry.device;
  const app = [browser, browser_version?.split(".")[0]].filter(Boolean).join(" ");
  const system = [os, os_version?.split(".")[0] && os !== "Windows" ? os_version.split(".")[0] : null].filter(Boolean).join(" ");
  return [app, system].filter(Boolean).join(" · ");
}

/**
 * Who has signed in, from what and from where, across the back office, the captain app and the store portal — and which of
 * those sessions are still open. Read from `login_histories`; the device comes from the request and the place from the IP
 * address, neither typed by the person signing in.
 */
export default function LoginHistoryPage() {
  const t = useT();
  const { locale } = useI18n();
  const { can } = useCan();
  const queryClient = useQueryClient();
  const canClose = can("login_history.manage");

  const [page, setPage] = useUrlState("page", 1, (value) => {
    const n = Number(value);
    return Number.isFinite(n) && n >= 1 ? n : null;
  });
  const [guard, setGuard] = useUrlState("guard", "", (value) => ((GUARDS as readonly string[]).includes(value) ? value : null));
  const [status, setStatus] = useUrlState("status", "", (value) => ((STATUSES as readonly string[]).includes(value) ? value : null));
  const [search, setSearch] = useUrlState("q", "", (value) => value);
  const [openOnly, setOpenOnly] = useUrlState("open", "", (value) => (value === "1" ? value : null));
  const [from, setFrom] = useUrlState("from", "", (value) => value);
  const [to, setTo] = useUrlState("to", "", (value) => value);

  const [detail, setDetail] = useState<LoginHistoryEntry | null>(null);
  const [closing, setClosing] = useState<LoginHistoryEntry | null>(null);

  const filters = useMemo(
    () => ({
      page,
      rows: 15,
      guard: (guard || undefined) as LoginGuardValue | undefined,
      status: (status || undefined) as LoginStatusValue | undefined,
      search: search || undefined,
      open_only: openOnly === "1" || undefined,
      from: from || undefined,
      to: to || undefined,
    }),
    [page, guard, status, search, openOnly, from, to],
  );

  const stats = useQuery({
    queryKey: queryKeys.loginHistory.stats,
    queryFn: async () => (await getLoginHistoryStats()).Model ?? null,
  });
  const list = useQuery({
    queryKey: queryKeys.loginHistory.list(filters),
    queryFn: () => getLoginHistory(filters),
  });

  const closeMutation = useMutation({
    mutationFn: closeLoginSession,
    onSuccess: (response) => {
      toast.success(response.Message || t("loginHistory.closed"));
      setClosing(null);
      setDetail(null);
      void queryClient.invalidateQueries({ queryKey: ["login-history"] });
    },
    onError: (error) => toast.error(friendlyErrorMessage(error, t)),
  });

  const rows = list.data?.Model ?? [];
  const hasFilters = Boolean(guard || status || search || openOnly || from || to);

  function clearFilters() {
    setPage(1);
    setGuard("");
    setStatus("");
    setSearch("");
    setOpenOnly("");
    setFrom("");
    setTo("");
  }

  const day = stats.data?.day;

  return (
    <div>
      <PageHeader title={t("loginHistory.title")} subtitle={t("loginHistory.subtitle")} />

      <div className="mb-6 grid gap-5 sm:grid-cols-2 lg:grid-cols-4">
        <StatCard
          label={t("loginHistory.signedIn")}
          value={formatNumber(day?.success, locale)}
          icon={LogIn}
          tone="success"
          hint={t("loginHistory.people", { count: formatNumber(day?.people, locale) })}
          loading={stats.isPending}
        />
        <StatCard
          label={t("loginHistory.refused")}
          value={formatNumber((day?.failed ?? 0) + (day?.blocked ?? 0), locale)}
          icon={ShieldAlert}
          tone={(day?.failed ?? 0) + (day?.blocked ?? 0) > 0 ? "warning" : "muted"}
          hint={t("loginHistory.refusedHint", { failed: formatNumber(day?.failed, locale), blocked: formatNumber(day?.blocked, locale) })}
          loading={stats.isPending}
        />
        <StatCard
          label={t("loginHistory.openSessions")}
          value={formatNumber(stats.data?.open_sessions, locale)}
          icon={Users}
          tone="primary"
          hint={t("loginHistory.openSessionsHint")}
          loading={stats.isPending}
        />
        <StatCard
          label={t("loginHistory.addresses")}
          value={formatNumber(day?.addresses, locale)}
          icon={Globe}
          tone="accent"
          hint={t("loginHistory.last24")}
          loading={stats.isPending}
        />
      </div>

      <Card>
        <div className="flex flex-col gap-3 kap-toolbar lg:flex-row lg:flex-wrap lg:items-center">
          <DebouncedSearch
            value={search}
            onChange={(value) => {
              setPage(1);
              setSearch(value);
            }}
            placeholder={t("loginHistory.search")}
            className="w-full lg:max-w-sm lg:flex-1"
          />
          <div className="flex flex-wrap items-center gap-2">
            <Select
              value={guard || "all"}
              onValueChange={(value) => {
                setPage(1);
                setGuard(value === "all" ? "" : value);
              }}
            >
              <SelectTrigger className="w-44" aria-label={t("loginHistory.area")}>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">{t("loginHistory.allAreas")}</SelectItem>
                {GUARDS.map((option) => (
                  <SelectItem key={option} value={option}>
                    {t(`loginHistory.guard.${option}`)}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <Select
              value={status || "all"}
              onValueChange={(value) => {
                setPage(1);
                setStatus(value === "all" ? "" : value);
              }}
            >
              <SelectTrigger className="w-40" aria-label={t("loginHistory.outcome")}>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">{t("loginHistory.allOutcomes")}</SelectItem>
                {STATUSES.map((option) => (
                  <SelectItem key={option} value={option}>
                    {t(`loginHistory.status.${option}`)}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <Button
              variant={openOnly ? "default" : "outline"}
              size="sm"
              aria-pressed={Boolean(openOnly)}
              onClick={() => {
                setPage(1);
                setOpenOnly(openOnly ? "" : "1");
              }}
            >
              {t("loginHistory.openOnly")}
            </Button>
            <Input
              type="date"
              value={from}
              onChange={(event) => {
                setPage(1);
                setFrom(event.target.value);
              }}
              aria-label={t("loginHistory.from")}
              className="w-40"
              dir="ltr"
            />
            <Input
              type="date"
              value={to}
              onChange={(event) => {
                setPage(1);
                setTo(event.target.value);
              }}
              aria-label={t("loginHistory.to")}
              className="w-40"
              dir="ltr"
            />
            {hasFilters ? (
              <Button variant="ghost" size="sm" onClick={clearFilters}>
                {t("common.clearFilters")}
              </Button>
            ) : null}
          </div>
        </div>

        {list.isPending ? (
          <TableSkeleton rows={8} cols={6} />
        ) : list.isError ? (
          <ErrorState message={friendlyErrorMessage(list.error, t)} onRetry={() => list.refetch()} />
        ) : rows.length === 0 ? (
          <EmptyState title={t("loginHistory.empty")} description={t("loginHistory.emptyHint")} icon={LogIn} />
        ) : (
          <>
            <div className="overflow-x-auto">
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead>{t("loginHistory.person")}</TableHead>
                    <TableHead>{t("loginHistory.device")}</TableHead>
                    <TableHead>{t("loginHistory.place")}</TableHead>
                    <TableHead>{t("loginHistory.outcome")}</TableHead>
                    <TableHead className="whitespace-nowrap">{t("loginHistory.when")}</TableHead>
                    <TableHead aria-label={t("common.actions")} />
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {rows.map((entry) => (
                    <HistoryRow
                      key={entry.uuid}
                      entry={entry}
                      canClose={canClose}
                      onDetails={() => setDetail(entry)}
                      onClose={() => setClosing(entry)}
                    />
                  ))}
                </TableBody>
              </Table>
            </div>
            <Pagination perPage={15} page={list.data!.Page} totalPages={list.data!.Total} records={list.data!.Records} onPageChange={setPage} />
          </>
        )}
      </Card>

      <DetailDialog entry={detail} onOpenChange={(open) => !open && setDetail(null)} canClose={canClose} onClose={(entry) => setClosing(entry)} />

      <ConfirmDialog
        open={closing !== null}
        onOpenChange={(open) => !open && setClosing(null)}
        title={t("loginHistory.closeTitle")}
        description={t("loginHistory.closeDescription", { name: closing?.user_name ?? closing?.identifier ?? "" })}
        confirmLabel={t("loginHistory.closeSession")}
        destructive
        loading={closeMutation.isPending}
        onConfirm={() => {
          if (closing) closeMutation.mutate(closing.uuid);
        }}
      />
    </div>
  );
}

function HistoryRow({
  entry,
  canClose,
  onDetails,
  onClose,
}: {
  entry: LoginHistoryEntry;
  canClose: boolean;
  onDetails: () => void;
  onClose: () => void;
}) {
  const t = useT();
  const { locale } = useI18n();
  const Icon = DEVICE_ICON[entry.device.type] ?? HelpCircle;
  const place = placeText(entry, t);

  return (
    <TableRow>
      <TableCell className="relative min-w-[12rem]">
        <StatusRail tone={STATUS_RAIL[entry.status]} />
        <p className="max-w-52 truncate font-medium text-foreground">{entry.user_name || entry.identifier || "—"}</p>
        <p className="max-w-52 truncate text-xs text-muted-foreground" dir="ltr">
          {entry.user_name ? entry.identifier : null}
        </p>
        <Badge variant="outline" className="mt-1">
          {entry.guard_label}
        </Badge>
      </TableCell>
      <TableCell className="min-w-[13rem]">
        <div className="flex items-start gap-2">
          <Icon className="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" aria-hidden />
          <div className="min-w-0">
            <p className="max-w-56 truncate text-foreground">{deviceLine(entry) || t("loginHistory.unknownDevice")}</p>
            {entry.device.name ? <p className="max-w-56 truncate text-xs text-muted-foreground">{entry.device.name}</p> : null}
          </div>
        </div>
      </TableCell>
      <TableCell className="min-w-[11rem]">
        <p className="max-w-48 text-foreground" title={entry.location.note ?? undefined}>
          {entry.precise ? (
            <span className="me-1.5 rounded bg-success/15 px-1 py-0.5 align-middle text-[10px] font-semibold text-success" title={t("loginHistory.deviceLocationHint")}>
              {t("loginHistory.gps")}
            </span>
          ) : entry.location.country_code ? (
            <span className="me-1.5 rounded bg-muted px-1 py-0.5 align-middle text-[10px] font-semibold text-muted-foreground" dir="ltr">
              {entry.location.country_code}
            </span>
          ) : null}
          {entry.precise ? entry.precise.place || t("loginHistory.coordinates", { lat: entry.precise.latitude.toFixed(4), lng: entry.precise.longitude.toFixed(4) }) : place}
        </p>
        <p className="numeric text-xs text-muted-foreground" dir="ltr">
          {entry.ip_address ?? "—"}
        </p>
      </TableCell>
      <TableCell>
        <StatusBadge variant={STATUS_VARIANT[entry.status]}>{entry.status_label}</StatusBadge>
        {entry.failure_label ? <p className="mt-1 max-w-40 text-xs text-muted-foreground">{entry.failure_label}</p> : null}
        {entry.status === "success" ? (
          <p className={entry.session_open ? "mt-1 text-xs text-success" : "mt-1 text-xs text-muted-foreground"}>
            {entry.session_open ? t("loginHistory.sessionOpen") : t("loginHistory.sessionEnded")}
          </p>
        ) : null}
      </TableCell>
      <TableCell>
        <p className="whitespace-nowrap text-xs text-muted-foreground" title={formatDateTime(entry.created_at, locale)}>
          {formatRelative(entry.created_at, locale)}
        </p>
      </TableCell>
      <TableCell>
        <div className="flex items-center gap-2">
          <Button variant="outline" size="sm" onClick={onDetails}>
            {t("loginHistory.details")}
          </Button>
          {canClose && entry.session_open ? (
            <Button variant="outline" size="sm" onClick={onClose}>
              <LogOut className="h-3.5 w-3.5" aria-hidden />
              {t("loginHistory.closeSession")}
            </Button>
          ) : null}
        </div>
      </TableCell>
    </TableRow>
  );
}

function placeText(entry: LoginHistoryEntry, t: ReturnType<typeof useT>): string {
  const { location } = entry;
  if (location.label) return location.label;
  if (location.status === "local") return t("loginHistory.placeLocal");
  if (location.status === "pending") return t("loginHistory.placePending");
  return t("loginHistory.placeUnknown");
}

function DetailDialog({
  entry,
  onOpenChange,
  canClose,
  onClose,
}: {
  entry: LoginHistoryEntry | null;
  onOpenChange: (open: boolean) => void;
  canClose: boolean;
  onClose: (entry: LoginHistoryEntry) => void;
}) {
  const t = useT();
  const { locale } = useI18n();

  const rows: [string, string | null | undefined][] = entry
    ? [
        [t("loginHistory.person"), entry.user_name],
        [t("loginHistory.identifier"), entry.identifier],
        [t("loginHistory.area"), entry.guard_label],
        [t("loginHistory.when"), formatDateTime(entry.created_at, locale)],
        [t("loginHistory.browser"), [entry.device.browser, entry.device.browser_version].filter(Boolean).join(" ")],
        [t("loginHistory.system"), [entry.device.os, entry.device.os_version].filter(Boolean).join(" ")],
        [t("loginHistory.deviceType"), t(`loginHistory.type.${entry.device.type}`)],
        [t("loginHistory.deviceName"), entry.device.name],
        [t("loginHistory.ip"), entry.ip_address],
        [t("loginHistory.deviceLocation"), entry.precise ? (entry.precise.place || t("loginHistory.coordinates", { lat: entry.precise.latitude.toFixed(5), lng: entry.precise.longitude.toFixed(5) })) : null],
        [t("loginHistory.accuracy"), entry.precise?.accuracy != null ? t("loginHistory.metres", { count: String(Math.round(entry.precise.accuracy)) }) : null],
        [t("loginHistory.ipPlace"), placeText(entry, t)],
        [t("loginHistory.timezone"), entry.location.timezone],
        [t("loginHistory.isp"), entry.location.isp],
      ]
    : [];

  const latitude = entry?.precise?.latitude ?? entry?.location.latitude ?? null;
  const longitude = entry?.precise?.longitude ?? entry?.location.longitude ?? null;

  return (
    <Dialog open={entry !== null} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-xl">
        <DialogHeader>
          <DialogTitle>{entry?.user_name || entry?.identifier || t("loginHistory.title")}</DialogTitle>
          <DialogDescription>
            {entry ? `${entry.status_label}${entry.failure_label ? ` · ${entry.failure_label}` : ""}` : null}
          </DialogDescription>
        </DialogHeader>
        {entry ? (
          <div className="space-y-5 text-sm">
            <dl className="grid grid-cols-1 gap-x-6 gap-y-3 sm:grid-cols-2">
              {rows
                .filter(([, value]) => value)
                .map(([label, value]) => (
                  <div key={label} className="min-w-0">
                    <dt className="text-xs text-muted-foreground">{label}</dt>
                    <dd className="break-words font-medium text-foreground">{value}</dd>
                  </div>
                ))}
            </dl>
            {entry.device.user_agent ? (
              <div>
                <p className="mb-1 text-xs text-muted-foreground">{t("loginHistory.userAgent")}</p>
                <p className="rounded-lg border bg-muted/30 p-3 text-xs leading-5 text-muted-foreground" dir="ltr">
                  {entry.device.user_agent}
                </p>
              </div>
            ) : null}
            <div className="flex flex-wrap items-center gap-2">
              {latitude !== null && longitude !== null ? (
                <a
                  href={`https://www.openstreetmap.org/?mlat=${latitude}&mlon=${longitude}#map=11/${latitude}/${longitude}`}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-xs font-medium text-primary hover:bg-muted"
                >
                  <ExternalLink className="h-3.5 w-3.5" aria-hidden />
                  {t("loginHistory.openMap")}
                </a>
              ) : null}
              {canClose && entry.session_open ? (
                <Button variant="outline" size="sm" onClick={() => onClose(entry)}>
                  <LogOut className="h-3.5 w-3.5" aria-hidden />
                  {t("loginHistory.closeSession")}
                </Button>
              ) : null}
            </div>
            {!entry.location.label && entry.location.note ? (
              <p className="rounded-lg border border-warning/40 bg-warning/5 p-3 text-xs leading-5 text-muted-foreground">
                {t("loginHistory.whyNoPlace")} <span dir="ltr">{entry.location.note}</span>
              </p>
            ) : null}
            <p className="text-xs leading-5 text-muted-foreground">{entry.precise ? t("loginHistory.deviceNote") : t("loginHistory.placeNote")}</p>
          </div>
        ) : null}
      </DialogContent>
    </Dialog>
  );
}
