"use client";

import { useState } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
import { Pencil, ShieldPlus } from "lucide-react";
import { PageHeader, Breadcrumbs } from "@/components/shared/page-header";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { FormField } from "@/components/ui/form-field";
import { Badge } from "@/components/ui/badge";
import { CheckboxField } from "@/components/ui/checkbox";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { EmptyState, ErrorState, TableSkeleton } from "@/components/shared/states";
import { getRoles, getPermissions, storeRole, updateRole } from "@/services/roles";
import { queryKeys } from "@/lib/query-keys";
import { useT } from "@/i18n";
import { applyFieldErrors, friendlyErrorMessage } from "@/lib/errors";
import { formatDateTime } from "@/lib/format";
import { useI18n } from "@/i18n";
import type { Permission, Role } from "@/types/admin";

const formSchema = z.object({
  name: z.string().min(1, "errors.required"),
  permissions: z.array(z.string()),
});

type FormValues = z.infer<typeof formSchema>;

/** Group the catalogue by its `group_label` so the form reads as a tree. */
function groupPermissions(permissions: Permission[]): { label: string; items: Permission[] }[] {
  const groups = new Map<string, Permission[]>();
  for (const permission of permissions) {
    const key = permission.group_label || permission.group;
    const list = groups.get(key) ?? [];
    list.push(permission);
    groups.set(key, list);
  }
  return Array.from(groups, ([label, items]) => ({ label, items }));
}

export default function SettingsRolesPage() {
  const t = useT();
  const { locale } = useI18n();
  const queryClient = useQueryClient();
  const [editing, setEditing] = useState<Role | null>(null);
  const [creating, setCreating] = useState(false);

  const rolesQuery = useQuery({
    queryKey: queryKeys.roles({ page: 1, rows: 25 }),
    queryFn: () => getRoles({ page: 1, rows: 25 }),
  });

  const permissionsQuery = useQuery({
    queryKey: queryKeys.permissions,
    queryFn: () => getPermissions(),
  });

  const roles = rolesQuery.data?.Model ?? [];
  const permissions = permissionsQuery.data?.Model ?? [];
  const groups = groupPermissions(permissions);

  const form = useForm<FormValues>({
    resolver: zodResolver(formSchema),
    mode: "onTouched",
    defaultValues: { name: "", permissions: [] },
  });

  const dialogOpen = creating || editing !== null;

  function openCreate() {
    form.reset({ name: "", permissions: [] });
    setEditing(null);
    setCreating(true);
  }

  function openEdit(role: Role) {
    form.reset({
      name: role.name,
      permissions: (role.permissions ?? []).map((permission) => permission.name),
    });
    setCreating(false);
    setEditing(role);
  }

  function closeDialog() {
    setCreating(false);
    setEditing(null);
  }

  function invalidate() {
    queryClient.invalidateQueries({ queryKey: ["roles"] });
  }

  async function handleSubmit(values: FormValues) {
    try {
      if (editing) {
        const response = await updateRole(editing.uuid, values);
        toast.success(response.Message || t("settings.roleUpdated"));
      } else {
        const response = await storeRole(values);
        toast.success(response.Message || t("settings.roleCreated"));
      }
      closeDialog();
      invalidate();
    } catch (error) {
      // A duplicate role name, or a permission the server does not know, is a field refusal.
      const shown = applyFieldErrors(
        error,
        (field, message) => form.setError(field as never, { message }),
        { only: ["name", "permissions"], collapse: ["permissions"] },
      );
      if (shown === 0) toast.error(friendlyErrorMessage(error, t));
    }
  }

  const watchedPermissions = form.watch("permissions");

  return (
    <div className="mx-auto max-w-5xl">
      <Breadcrumbs items={[{ label: t("nav.settings"), href: "/settings" }, { label: t("settings.rolesTitle") }]} />
      <PageHeader
        title={t("settings.rolesTitle")}
        subtitle={t("settings.rolesSubtitle")}
        actions={
          <Button onClick={openCreate}>
            <ShieldPlus className="h-4 w-4" aria-hidden />
            {t("common.create")}
          </Button>
        }
      />

      {rolesQuery.isLoading || permissionsQuery.isLoading ? (
        <TableSkeleton rows={4} cols={3} />
      ) : rolesQuery.isError || permissionsQuery.isError ? (
        <ErrorState
          message={friendlyErrorMessage(rolesQuery.error ?? permissionsQuery.error, t)}
          onRetry={() => {
            rolesQuery.refetch();
            permissionsQuery.refetch();
          }}
        />
      ) : roles.length === 0 ? (
        <EmptyState title={t("settings.rolesEmpty")} />
      ) : (
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
          {roles.map((role) => (
            <Card key={role.uuid}>
              <CardContent className="pt-5">
                <div className="flex items-start justify-between gap-2">
                  <div className="min-w-0">
                    <p className="truncate font-semibold text-foreground">{role.name}</p>
                    <p className="mt-1 text-xs text-muted-foreground">
                      {(role.permissions ?? []).length} {t("settings.permissionsEmpty")}
                    </p>
                    <div className="mt-2 flex flex-wrap gap-1">
                      {role.is_super_admin ? (
                        <Badge variant="primary">{t("settings.superAdminBadge")}</Badge>
                      ) : null}
                      {(role.permissions ?? []).slice(0, 3).map((permission) => (
                        <Badge key={permission.uuid} variant="outline">{permission.name}</Badge>
                      ))}
                      {(role.permissions ?? []).length > 3 ? (
                        <Badge variant="secondary">+{(role.permissions ?? []).length - 3}</Badge>
                      ) : null}
                    </div>
                  </div>
                  <Button variant="ghost" size="icon-sm" onClick={() => openEdit(role)} aria-label={t("common.edit")}>
                    <Pencil className="h-4 w-4" />
                  </Button>
                </div>
                {role.created_at ? (
                  <p className="mt-3 border-t pt-3 text-[11px] text-muted-foreground">
                    {t("common.createdAt")}: {formatDateTime(role.created_at, locale)}
                  </p>
                ) : null}
              </CardContent>
            </Card>
          ))}
        </div>
      )}

      <Dialog open={dialogOpen} onOpenChange={(open) => !open && closeDialog()}>
        <DialogContent className="max-w-lg">
          <DialogHeader>
            <DialogTitle>{creating ? t("common.create") : t("common.edit")} — {t("settings.rolesTitle")}</DialogTitle>
            <DialogDescription>{t("settings.rolesSubtitle")}</DialogDescription>
          </DialogHeader>
          <form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4" noValidate>
            <FormField label="Name" htmlFor="role-name" required error={form.formState.errors.name?.message}>
              <Input id="role-name" dir="ltr" {...form.register("name")} />
            </FormField>
            {/* One control as far as the operator is concerned: the server refuses a permission
                by position, and those collapse onto the group. */}
            <FormField
              label={t("settings.permissionsLabel")}
              required
              error={form.formState.errors.permissions?.message}
            >
              <div className="max-h-72 space-y-3 overflow-y-auto rounded-lg border p-3">
                {groups.length === 0 ? (
                  <p className="text-xs text-muted-foreground">{t("settings.permissionsEmpty")}</p>
                ) : (
                  groups.map((group) => (
                    <div key={group.label}>
                      <p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                        {group.label}
                      </p>
                      <div className="grid gap-2 sm:grid-cols-2">
                        {group.items.map((permission) => (
                          <CheckboxField
                            key={permission.uuid}
                            id={`perm-${permission.uuid}`}
                            label={permission.label}
                            checked={watchedPermissions?.includes(permission.name) ?? false}
                            onCheckedChange={(checked) => {
                              const current = form.getValues("permissions");
                              form.setValue(
                                "permissions",
                                checked
                                  ? Array.from(new Set([...current, permission.name]))
                                  : current.filter((name) => name !== permission.name),
                              );
                            }}
                          />
                        ))}
                      </div>
                    </div>
                  ))
                )}
              </div>
            </FormField>
            <DialogFooter>
              <Button type="button" variant="outline" onClick={closeDialog}>
                {t("common.cancel")}
              </Button>
              <Button type="submit" loading={form.formState.isSubmitting}>
                {t("common.save")}
              </Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    </div>
  );
}