import { createFileRoute } from "@tanstack/react-router";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useServerFn } from "@tanstack/react-start";
import { useEffect, useMemo, useState } from "react";
import { supabase } from "@/integrations/supabase/client";
import { toast } from "sonner";
import { Shield, Trash2, Plus, Search } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { RequireRole } from "@/hooks/use-roles";
import {
  listUsersWithRoles,
  grantRole,
  revokeRole,
} from "@/lib/roles-admin.functions";

export const Route = createFileRoute("/_authenticated/roles")({
  component: RolesPage,
});

const ROLE_LABELS: Record<string, string> = {
  super_admin: "Super Admin",
  company_admin: "Company Admin",
  ops_manager: "Security Manager",
  security_officer: "Security Officer",
  supervisor: "Supervisor",
  guard: "Guard",
};
const ROLE_OPTIONS = Object.keys(ROLE_LABELS) as Array<keyof typeof ROLE_LABELS>;

function RolesPage() {
  return (
    <RequireRole any={["super_admin", "admin", "company_admin"]}>
      <RolesAdmin />
    </RequireRole>
  );
}

function RolesAdmin() {
  const qc = useQueryClient();
  const list = useServerFn(listUsersWithRoles);
  const grant = useServerFn(grantRole);
  const revoke = useServerFn(revokeRole);

  const { data, isLoading } = useQuery({
    queryKey: ["users-with-roles"],
    queryFn: () => list(),
  });

  const [q, setQ] = useState("");
  const [roleFilter, setRoleFilter] = useState<string>("all");
  const [pending, setPending] = useState<Record<string, string>>({});

  useEffect(() => {
    const ch = supabase
      .channel("user_roles_rt")
      .on(
        "postgres_changes",
        { event: "*", schema: "public", table: "user_roles" },
        () => qc.invalidateQueries({ queryKey: ["users-with-roles"] }),
      )
      .subscribe();
    return () => {
      supabase.removeChannel(ch);
    };
  }, [qc]);

  const filtered = useMemo(() => {
    const term = q.trim().toLowerCase();
    let rows = data ?? [];
    if (roleFilter === "none") rows = rows.filter((u) => u.roles.length === 0);
    else if (roleFilter !== "all") rows = rows.filter((u) => u.roles.includes(roleFilter));
    if (!term) return rows;
    return rows.filter(
      (u) =>
        (u.full_name ?? "").toLowerCase().includes(term) ||
        (u.email ?? "").toLowerCase().includes(term) ||
        (u.phone ?? "").toLowerCase().includes(term),
    );
  }, [data, q, roleFilter]);

  const stats = useMemo(() => {
    const rows = data ?? [];
    const counts: Record<string, number> = {};
    for (const u of rows) for (const r of u.roles) counts[r] = (counts[r] ?? 0) + 1;
    return { total: rows.length, noRole: rows.filter((u) => u.roles.length === 0).length, counts };
  }, [data]);

  const grantMut = useMutation({
    mutationFn: (vars: { user_id: string; role: string }) =>
      grant({ data: vars as never }),
    onSuccess: (_d, vars) => {
      toast.success("Role granted");
      setPending((p) => {
        const n = { ...p };
        delete n[vars.user_id];
        return n;
      });
      qc.invalidateQueries({ queryKey: ["users-with-roles"] });
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const revokeMut = useMutation({
    mutationFn: (vars: { user_id: string; role: string }) =>
      revoke({ data: vars as never }),
    onSuccess: () => {
      toast.success("Role revoked");
      qc.invalidateQueries({ queryKey: ["users-with-roles"] });
    },
    onError: (e: Error) => toast.error(e.message),
  });

  return (
    <div className="space-y-6 max-w-5xl mx-auto">
      <div className="flex items-center gap-3">
        <Shield className="h-7 w-7 text-primary" />
        <div>
          <h1 className="text-3xl font-bold tracking-tight">User Roles</h1>
          <p className="text-sm text-muted-foreground">
            Grant or revoke roles for users.
          </p>
        </div>
      </div>

      <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
        <Card><CardContent className="p-4"><div className="text-xs text-muted-foreground">Total users</div><div className="text-2xl font-bold">{stats.total}</div></CardContent></Card>
        <Card><CardContent className="p-4"><div className="text-xs text-muted-foreground">No role</div><div className="text-2xl font-bold">{stats.noRole}</div></CardContent></Card>
        <Card><CardContent className="p-4"><div className="text-xs text-muted-foreground">Admins</div><div className="text-2xl font-bold">{(stats.counts.super_admin ?? 0) + (stats.counts.company_admin ?? 0) + (stats.counts.admin ?? 0)}</div></CardContent></Card>
        <Card><CardContent className="p-4"><div className="text-xs text-muted-foreground">Guards</div><div className="text-2xl font-bold">{stats.counts.guard ?? 0}</div></CardContent></Card>
      </div>

      <div className="flex flex-col sm:flex-row gap-2">
        <div className="relative flex-1">
          <Search className="h-4 w-4 absolute left-3 top-3 text-muted-foreground" />
          <Input
            placeholder="Search name, email, phone…"
            value={q}
            onChange={(e) => setQ(e.target.value)}
            className="pl-9"
          />
        </div>
        <Select value={roleFilter} onValueChange={setRoleFilter}>
          <SelectTrigger className="w-full sm:w-56"><SelectValue /></SelectTrigger>
          <SelectContent>
            <SelectItem value="all">All users</SelectItem>
            <SelectItem value="none">No role assigned</SelectItem>
            {ROLE_OPTIONS.map((r) => (
              <SelectItem key={r} value={r}>{ROLE_LABELS[r]}</SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>

      {isLoading ? (
        <p className="text-muted-foreground">Loading…</p>
      ) : filtered.length === 0 ? (
        <p className="text-muted-foreground">No users found.</p>
      ) : (
        <div className="grid gap-3">
          {filtered.map((u) => {
            const available = ROLE_OPTIONS.filter((r) => !u.roles.includes(r));
            const sel = pending[u.id] ?? available[0] ?? "";
            return (
              <Card key={u.id}>
                <CardHeader className="pb-3">
                  <CardTitle className="text-base flex items-center justify-between gap-2 flex-wrap">
                    <span>{u.full_name || u.email || u.id.slice(0, 8)}</span>
                    <span className="text-xs font-normal text-muted-foreground">
                      {u.email}
                      {u.phone ? ` · ${u.phone}` : ""}
                    </span>
                  </CardTitle>
                </CardHeader>
                <CardContent className="space-y-3">
                  <div className="flex flex-wrap gap-2">
                    {u.roles.length === 0 && (
                      <span className="text-sm text-muted-foreground">
                        No roles assigned
                      </span>
                    )}
                    {u.roles.map((r) => (
                      <Badge
                        key={r}
                        variant="secondary"
                        className="flex items-center gap-1"
                      >
                        {ROLE_LABELS[r] ?? r}
                        <button
                          type="button"
                          aria-label={`Remove ${r}`}
                          className="hover:text-destructive"
                          onClick={() =>
                            revokeMut.mutate({ user_id: u.id, role: r })
                          }
                          disabled={revokeMut.isPending}
                        >
                          <Trash2 className="h-3 w-3" />
                        </button>
                      </Badge>
                    ))}
                  </div>
                  {available.length > 0 && (
                    <div className="flex items-center gap-2">
                      <Select
                        value={sel}
                        onValueChange={(v) =>
                          setPending((p) => ({ ...p, [u.id]: v }))
                        }
                      >
                        <SelectTrigger className="w-56">
                          <SelectValue />
                        </SelectTrigger>
                        <SelectContent>
                          {available.map((r) => (
                            <SelectItem key={r} value={r}>
                              {ROLE_LABELS[r]}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                      <Button
                        size="sm"
                        onClick={() =>
                          grantMut.mutate({ user_id: u.id, role: sel })
                        }
                        disabled={!sel || grantMut.isPending}
                      >
                        <Plus className="h-4 w-4 mr-1" /> Grant
                      </Button>
                    </div>
                  )}
                </CardContent>
              </Card>
            );
          })}
        </div>
      )}
    </div>
  );
}