"use client";

import { useEffect, useMemo, useState, useCallback } from "react";
import { useTranslations } from "next-intl";
import {
  Plus,
  Users,
  KeyRound,
  Search,
  Pencil,
  Trash2,
  Shield,
  Lock,
} from "lucide-react";
import Button from "@/components/ui/Button";
import Badge from "@/components/ui/Badge";
import ConfirmModal from "@/components/ui/ConfirmModal";
import RoleFormModal from "@/components/roles/RoleFormModal";
import { readApiJson, toastPromise } from "@/lib/toast";

interface Permission {
  id: string;
  name: string;
  module: string;
  action: string;
  description: string | null;
}

interface Role {
  id: string;
  name: string;
  description: string | null;
  isSystem: boolean;
  _count: { users: number };
  permissions: { permission: Permission }[];
}

interface Props {
  canCreate: boolean;
  canUpdate: boolean;
  canDelete: boolean;
}

const EMPTY_FORM = { name: "", description: "", permissionIds: [] as string[] };

export default function RolesClient({ canCreate, canUpdate, canDelete }: Props) {
  const t = useTranslations("roles");
  const tc = useTranslations("common");
  const [roles, setRoles] = useState<Role[]>([]);
  const [allPerms, setAllPerms] = useState<Permission[]>([]);
  const [loading, setLoading] = useState(true);
  const [search, setSearch] = useState("");
  const [showModal, setShowModal] = useState(false);
  const [editRole, setEditRole] = useState<Role | null>(null);
  const [formSeed, setFormSeed] = useState(EMPTY_FORM);
  const [saving, setSaving] = useState(false);
  const [deleteTarget, setDeleteTarget] = useState<Role | null>(null);
  const [deleting, setDeleting] = useState(false);

  const fetchRoles = useCallback(async () => {
    setLoading(true);
    const res = await fetch("/api/roles");
    const data = await res.json();
    setRoles(Array.isArray(data) ? data : []);
    setLoading(false);
  }, []);

  useEffect(() => {
    fetchRoles();
  }, [fetchRoles]);

  useEffect(() => {
    fetch("/api/permissions")
      .then((r) => r.json())
      .then((d) => setAllPerms(Array.isArray(d) ? d : []));
  }, []);

  function openCreate() {
    setEditRole(null);
    setFormSeed({ name: "", description: "", permissionIds: [] });
    setShowModal(true);
  }

  function openEdit(role: Role) {
    setEditRole(role);
    setFormSeed({
      name: role.name,
      description: role.description ?? "",
      permissionIds: role.permissions.map((rp) => rp.permission.id),
    });
    setShowModal(true);
  }

  async function handleSave(form: {
    name: string;
    description: string;
    permissionIds: string[];
  }) {
    setSaving(true);

    const url = editRole ? `/api/roles/${editRole.id}` : "/api/roles";
    const method = editRole ? "PATCH" : "POST";

    try {
      await toastPromise(
        readApiJson(
          await fetch(url, {
            method,
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(form),
          }),
          tc("somethingWrong")
        ),
        {
          loading: tc("saving"),
          success: editRole ? tc("updatedSuccess") : tc("createdSuccess"),
        }
      );
      setShowModal(false);
      fetchRoles();
    } catch {
      // surfaced via toast
    } finally {
      setSaving(false);
    }
  }

  async function handleDelete() {
    if (!deleteTarget) return;
    setDeleting(true);

    try {
      await toastPromise(
        readApiJson(
          await fetch(`/api/roles/${deleteTarget.id}`, { method: "DELETE" }),
          tc("somethingWrong")
        ),
        {
          loading: tc("loading"),
          success: tc("deletedSuccess"),
        }
      );
      setDeleteTarget(null);
      fetchRoles();
    } catch {
      // surfaced via toast
    } finally {
      setDeleting(false);
    }
  }

  const filteredRoles = useMemo(() => {
    const q = search.trim().toLowerCase();
    if (!q) return roles;
    return roles.filter(
      (role) =>
        role.name.toLowerCase().includes(q) ||
        (role.description?.toLowerCase().includes(q) ?? false)
    );
  }, [roles, search]);

  const copySources = useMemo(
    () => (editRole ? roles.filter((r) => r.id !== editRole.id) : roles),
    [roles, editRole]
  );

  return (
    <div className="w-full space-y-5 sm:space-y-6">
      <div className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
        <div>
          <h1 className="text-xl font-semibold tracking-tight sm:text-2xl">{t("title")}</h1>
          <p className="mt-1 text-sm text-[var(--text-muted)]">
            {t("total", { count: roles.length })}
          </p>
        </div>
        {canCreate && (
          <Button onClick={openCreate} className="w-full sm:w-auto">
            <Plus className="h-4 w-4" />
            {t("addRole")}
          </Button>
        )}
      </div>

      <div className="overflow-hidden rounded-2xl border border-[var(--border)] bg-[var(--bg-elevated)]">
        <div className="border-b border-[var(--border)] p-4 sm:px-5">
          <div className="relative w-full sm:max-w-xs">
            <Search className="pointer-events-none absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[var(--text-faint)]" />
            <input
              type="search"
              placeholder={t("searchPlaceholder")}
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              className="w-full rounded-lg border border-[var(--border)] bg-[var(--bg)] py-2.5 pe-3.5 ps-10 text-sm text-[var(--text)] placeholder:text-[var(--text-faint)] transition focus:border-[var(--accent)]/60 focus:outline-none focus:ring-2 focus:ring-[var(--accent)]/40"
            />
          </div>
        </div>

        {loading ? (
          <div className="grid gap-4 p-4 sm:grid-cols-2 sm:p-5">
            {Array.from({ length: 4 }).map((_, i) => (
              <div key={i} className="h-44 skeleton rounded-xl" />
            ))}
          </div>
        ) : filteredRoles.length === 0 ? (
          <div className="flex flex-col items-center gap-2 px-6 py-16 text-center">
            <div className="mb-1 flex h-12 w-12 items-center justify-center rounded-full bg-[var(--bg-hover)] text-[var(--text-faint)]">
              <Shield className="h-5 w-5" />
            </div>
            <p className="text-sm font-medium text-[var(--text)]">{t("noRoles")}</p>
            <p className="text-xs text-[var(--text-faint)]">{t("noRolesHint")}</p>
          </div>
        ) : (
          <div className="grid gap-4 p-4 sm:grid-cols-2 sm:p-5">
            {filteredRoles.map((role) => {
              const showActions = !role.isSystem && (canUpdate || canDelete);
              return (
                <div
                  key={role.id}
                  className="group flex flex-col rounded-2xl border border-[var(--border)] bg-[var(--bg)]/40 p-4 transition-colors hover:border-[var(--accent)]/25 hover:bg-[var(--bg-hover)]/20 sm:p-5"
                >
                  <div className="mb-4 flex items-start justify-between gap-3">
                    <div className="min-w-0">
                      <div className="flex flex-wrap items-center gap-2">
                        <h3 className="truncate text-base font-semibold tracking-tight">
                          {role.name}
                        </h3>
                        {role.isSystem && (
                          <Badge variant="role" role={role.name}>
                            {tc("system")}
                          </Badge>
                        )}
                      </div>
                      <p className="mt-1.5 line-clamp-2 text-xs leading-relaxed text-[var(--text-faint)]">
                        {role.description || t("descPlaceholder")}
                      </p>
                    </div>
                    {showActions && (
                      <div className="flex shrink-0 items-center gap-1 opacity-100 transition-opacity lg:opacity-0 lg:group-hover:opacity-100">
                        {canUpdate && (
                          <Button
                            variant="ghost"
                            size="sm"
                            onClick={() => openEdit(role)}
                            aria-label={tc("edit")}
                          >
                            <Pencil className="h-3.5 w-3.5" />
                          </Button>
                        )}
                        {canDelete && (
                          <Button
                            variant="ghost"
                            size="sm"
                            onClick={() => setDeleteTarget(role)}
                            aria-label={tc("delete")}
                            className="text-red-400 hover:bg-red-500/10 hover:text-red-300"
                          >
                            <Trash2 className="h-3.5 w-3.5" />
                          </Button>
                        )}
                      </div>
                    )}
                    {role.isSystem && (
                      <div
                        className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-[var(--text-faint)]"
                        title={t("systemProtected")}
                      >
                        <Lock className="h-3.5 w-3.5" />
                      </div>
                    )}
                  </div>

                  <div className="mb-4 flex flex-wrap items-center gap-3 text-xs text-[var(--text-muted)]">
                    <span className="inline-flex items-center gap-1.5 rounded-md border border-[var(--border)] bg-[var(--bg-elevated)] px-2 py-1">
                      <Users className="h-3.5 w-3.5 text-[var(--text-faint)]" />
                      {t("usersCount", { count: role._count.users })}
                    </span>
                    <span className="inline-flex items-center gap-1.5 rounded-md border border-[var(--border)] bg-[var(--bg-elevated)] px-2 py-1">
                      <KeyRound className="h-3.5 w-3.5 text-[var(--text-faint)]" />
                      {t("permsCount", { count: role.permissions.length })}
                    </span>
                  </div>

                  <div className="mt-auto flex flex-wrap gap-1.5">
                    {role.permissions.slice(0, 5).map((rp) => (
                      <Badge key={rp.permission.id}>{rp.permission.name}</Badge>
                    ))}
                    {role.permissions.length > 5 && (
                      <Badge>+{role.permissions.length - 5}</Badge>
                    )}
                    {role.permissions.length === 0 && (
                      <span className="text-xs text-[var(--text-faint)]">—</span>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </div>

      <RoleFormModal
        key={editRole?.id ?? "create"}
        open={showModal}
        isEdit={Boolean(editRole)}
        initial={formSeed}
        allPerms={allPerms}
        roles={copySources}
        saving={saving}
        onClose={() => setShowModal(false)}
        onSubmit={handleSave}
      />

      <ConfirmModal
        open={Boolean(deleteTarget)}
        title={tc("confirmTitle")}
        description={
          deleteTarget
            ? `${t("deleteConfirm")} (${deleteTarget.name})`
            : t("deleteConfirm")
        }
        loading={deleting}
        onConfirm={handleDelete}
        onCancel={() => {
          if (!deleting) setDeleteTarget(null);
        }}
      />
    </div>
  );
}
