"use client";

import { FormEvent, useMemo, useState } from "react";
import { Check, Pencil, Plus, Power, X } from "lucide-react";
import { useRouter } from "next/navigation";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Select } from "@/components/ui/select";
import type { ApiResult } from "@/modules/core/server/api";
import type { JoinRequest, Organization, PublicAccount, RoleDefinition } from "@/modules/core/types";

type UserManagementClientProps = {
  canManageAccounts?: boolean;
  organizations: Organization[];
  roles: RoleDefinition[];
  joinRequests: JoinRequest[];
};

function getOrganizationRoles(roles: RoleDefinition[], organizationId: string): RoleDefinition[] {
  return roles.filter((role) => role.scope === "organization" && role.organizationId === organizationId && role.isEnabled);
}

export function UserManagementClient({
  canManageAccounts = false,
  organizations,
  roles,
  joinRequests,
}: UserManagementClientProps): React.ReactElement {
  const router = useRouter();
  const [isCreateOpen, setIsCreateOpen] = useState(false);
  const [selectedOrganizationId, setSelectedOrganizationId] = useState("");
  const [reviewRoleByRequestId, setReviewRoleByRequestId] = useState<Record<string, string>>({});
  const [message, setMessage] = useState("");
  const [isPending, setIsPending] = useState(false);

  const organizationRoles = useMemo(
    () => getOrganizationRoles(roles, selectedOrganizationId),
    [roles, selectedOrganizationId],
  );
  const pendingJoinRequests = joinRequests.filter((request) => request.status === "pending");

  function openCreateDialog(): void {
    setMessage("");
    setIsCreateOpen(true);
  }

  function closeCreateDialog(): void {
    if (isPending) {
      return;
    }

    setIsCreateOpen(false);
  }

  async function handleCreateAccount(event: FormEvent<HTMLFormElement>): Promise<void> {
    event.preventDefault();
    if (!canManageAccounts) {
      setMessage("当前角色无权创建用户");
      return;
    }

    setMessage("");

    const formData = new FormData(event.currentTarget);
    const organizationId = String(formData.get("organizationId") ?? "");
    const roleId = String(formData.get("roleId") ?? "");
    if (!organizationId || !roleId) {
      setMessage("请选择机构和角色");
      return;
    }

    setIsPending(true);
    const response = await fetch("/api/settings/accounts", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        organizationId,
        roleId,
        name: String(formData.get("name") ?? ""),
        email: String(formData.get("email") ?? ""),
        avatarUrl: String(formData.get("avatarUrl") ?? ""),
        password: String(formData.get("password") ?? ""),
      }),
    });
    const result = (await response.json()) as ApiResult<{ account: unknown }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    setMessage(result.reason);
    setIsCreateOpen(false);
    event.currentTarget.reset();
    router.refresh();
  }

  async function reviewJoinRequest(requestId: string, decision: "approved" | "rejected", roleId: string): Promise<void> {
    if (!canManageAccounts) {
      setMessage("当前角色无权审批加入申请");
      return;
    }

    setMessage("");
    setIsPending(true);
    const response = await fetch(`/api/settings/join-requests/${requestId}`, {
      method: "PATCH",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ decision, roleId }),
    });
    const result = (await response.json()) as ApiResult<{ joinRequest: unknown }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    setMessage(result.reason);
    router.refresh();
  }

  return (
    <section className="grid gap-4 xl:grid-cols-[0.9fr_1.1fr]">
      <Card>
        <CardHeader className="gap-4 md:flex-row md:items-start md:justify-between">
          <div>
            <CardTitle>用户操作</CardTitle>
            <CardDescription>创建账号和审批入口已收进弹窗，列表区域保持可扫描。</CardDescription>
          </div>
          <Button
            disabled={!canManageAccounts || organizations.length === 0}
            onClick={openCreateDialog}
            type="button"
          >
            <Plus className="size-4" aria-hidden="true" />
            创建用户
          </Button>
        </CardHeader>
        <CardContent className="grid gap-3">
          <div className="grid gap-3 sm:grid-cols-3">
            <div className="rounded-md border bg-secondary/20 p-3">
              <p className="text-xs text-muted-foreground">可选机构</p>
              <p className="mt-1 text-2xl font-semibold">{organizations.length}</p>
            </div>
            <div className="rounded-md border bg-secondary/20 p-3">
              <p className="text-xs text-muted-foreground">当前机构角色</p>
              <p className="mt-1 text-2xl font-semibold">{organizationRoles.length}</p>
            </div>
            <div className="rounded-md border bg-secondary/20 p-3">
              <p className="text-xs text-muted-foreground">待审批</p>
              <p className="mt-1 text-2xl font-semibold">{pendingJoinRequests.length}</p>
            </div>
          </div>
          {message ? (
            <p className="rounded-md bg-secondary px-3 py-2 text-sm text-secondary-foreground" role="status">
              {message}
            </p>
          ) : null}
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle>加入申请审批</CardTitle>
          <CardDescription>公开注册选择机构后进入这里审批。</CardDescription>
        </CardHeader>
        <CardContent className="space-y-3">
          {pendingJoinRequests.map((request) => {
            const requestRoles = getOrganizationRoles(roles, request.organizationId);
            const selectedRoleId = reviewRoleByRequestId[request.id] ?? "";

            return (
              <div key={request.id} className="rounded-md border p-3">
                <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
                  <div>
                    <p className="font-medium">{request.accountName}</p>
                    <p className="text-xs text-muted-foreground">{request.accountEmail}</p>
                    <p className="mt-2 text-sm text-muted-foreground">{request.organizationName}</p>
                  </div>
                  <Badge variant="warning">待审批</Badge>
                </div>
                <div className="mt-3 grid gap-2 sm:grid-cols-[1fr_auto_auto]">
                  <Select
                    aria-label={`${request.accountName} 审批角色`}
                    disabled={requestRoles.length === 0}
                    onValueChange={(roleId) =>
                      setReviewRoleByRequestId((current) => ({ ...current, [request.id]: roleId }))
                    }
                    options={[
                      { value: "", label: "选择审批角色", disabled: true },
                      ...requestRoles.map((role) => ({ value: role.id, label: role.label })),
                    ]}
                    value={selectedRoleId}
                  />
                  <Button
                    disabled={isPending || !selectedRoleId || !canManageAccounts}
                    onClick={() => void reviewJoinRequest(request.id, "approved", selectedRoleId)}
                    size="sm"
                    type="button"
                  >
                    <Check className="size-4" aria-hidden="true" />
                    通过
                  </Button>
                  <Button
                    disabled={isPending || !canManageAccounts}
                    onClick={() => void reviewJoinRequest(request.id, "rejected", "")}
                    size="sm"
                    type="button"
                    variant="outline"
                  >
                    <X className="size-4" aria-hidden="true" />
                    拒绝
                  </Button>
                </div>
              </div>
            );
          })}
          {pendingJoinRequests.length === 0 ? <p className="text-sm text-muted-foreground">暂无待审批申请</p> : null}
        </CardContent>
      </Card>

      <Dialog
        description="管理员创建账号后立即分配到机构和角色。"
        onClose={closeCreateDialog}
        open={isCreateOpen}
        title="创建机构用户"
      >
        <form className="grid gap-3" onSubmit={handleCreateAccount}>
          <label className="grid gap-2 text-sm">
            <span className="font-medium">机构</span>
            <Select
              aria-label="机构"
              name="organizationId"
              onValueChange={setSelectedOrganizationId}
              options={[
                { value: "", label: "选择机构", disabled: true },
                ...organizations.map((organization) => ({ value: organization.id, label: organization.name })),
              ]}
              required
              value={selectedOrganizationId}
            />
          </label>

          <label className="grid gap-2 text-sm">
            <span className="font-medium">角色</span>
            <Select
              aria-label="角色"
              defaultValue=""
              disabled={organizationRoles.length === 0}
              key={selectedOrganizationId}
              name="roleId"
              options={[
                { value: "", label: selectedOrganizationId ? "选择角色" : "先选择机构", disabled: true },
                ...organizationRoles.map((role) => ({ value: role.id, label: role.label })),
              ]}
              required
            />
          </label>

          <label className="grid gap-2 text-sm">
            <span className="font-medium">姓名</span>
            <Input name="name" required />
          </label>
          <label className="grid gap-2 text-sm">
            <span className="font-medium">邮箱</span>
            <Input name="email" required type="email" />
          </label>
          <label className="grid gap-2 text-sm">
            <span className="font-medium">头像 URL</span>
            <Input name="avatarUrl" placeholder="https://example.com/avatar.png" type="url" />
          </label>
          <label className="grid gap-2 text-sm">
            <span className="font-medium">初始密码</span>
            <Input minLength={6} name="password" required type="password" />
          </label>

          <div className="flex flex-col-reverse gap-2 pt-1 sm:flex-row sm:justify-end">
            <Button disabled={isPending} onClick={closeCreateDialog} type="button" variant="outline">
              取消
            </Button>
            <Button disabled={isPending || organizationRoles.length === 0} type="submit">
              <Plus className="size-4" aria-hidden="true" />
              创建用户
            </Button>
          </div>
        </form>
        {message ? (
          <p className="mt-3 rounded-md bg-secondary px-3 py-2 text-sm text-secondary-foreground" role="status">
            {message}
          </p>
        ) : null}
      </Dialog>
    </section>
  );
}

type UserAccountActionsProps = {
  account: PublicAccount;
  currentAccountId: string;
  organizations: Organization[];
  roles: RoleDefinition[];
};

export function UserAccountActions({
  account,
  currentAccountId,
  organizations,
  roles,
}: UserAccountActionsProps): React.ReactElement {
  const router = useRouter();
  const [isEditOpen, setIsEditOpen] = useState(false);
  const [selectedOrganizationId, setSelectedOrganizationId] = useState(() => account.organizationId ?? "");
  const [message, setMessage] = useState("");
  const [isPending, setIsPending] = useState(false);
  const organizationRoles = useMemo(
    () => getOrganizationRoles(roles, selectedOrganizationId),
    [roles, selectedOrganizationId],
  );
  const defaultRoleId = organizationRoles.find((role) => role.key === account.role || role.id === account.role)?.id ?? "";
  const isCurrentAccount = account.id === currentAccountId;

  async function updateAccount(payload: Record<string, string>): Promise<void> {
    setMessage("");
    setIsPending(true);
    const response = await fetch(`/api/settings/accounts/${account.id}`, {
      method: "PATCH",
      headers: { "content-type": "application/json" },
      body: JSON.stringify(payload),
    });
    const result = (await response.json()) as ApiResult<{ account: PublicAccount }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    setMessage(result.reason);
    setIsEditOpen(false);
    router.refresh();
  }

  async function disableAccount(): Promise<void> {
    setMessage("");
    setIsPending(true);
    const response = await fetch(`/api/settings/accounts/${account.id}`, {
      method: "DELETE",
    });
    const result = (await response.json()) as ApiResult<{ account: PublicAccount }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    router.refresh();
  }

  async function handleSubmit(event: FormEvent<HTMLFormElement>): Promise<void> {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    await updateAccount({
      name: String(formData.get("name") ?? ""),
      avatarUrl: String(formData.get("avatarUrl") ?? ""),
      status: String(formData.get("status") ?? ""),
      organizationId: String(formData.get("organizationId") ?? ""),
      roleId: String(formData.get("roleId") ?? ""),
    });
  }

  return (
    <div className="flex items-center justify-end gap-2">
      <Button onClick={() => setIsEditOpen(true)} size="sm" type="button" variant="outline">
        <Pencil className="size-4" aria-hidden="true" />
        编辑
      </Button>
      {account.status === "disabled" ? (
        <Button
          disabled={isPending}
          onClick={() => void updateAccount({ status: "active" })}
          size="sm"
          type="button"
          variant="outline"
        >
          <Power className="size-4" aria-hidden="true" />
          启用
        </Button>
      ) : (
        <Button
          disabled={isPending || isCurrentAccount}
          onClick={() => void disableAccount()}
          size="sm"
          type="button"
          variant="destructive"
        >
          <Power className="size-4" aria-hidden="true" />
          停用
        </Button>
      )}
      <Dialog
        description="调整账号基础信息、状态和机构角色。"
        onClose={() => setIsEditOpen(false)}
        open={isEditOpen}
        title="编辑用户"
      >
        <form className="grid gap-4" onSubmit={handleSubmit}>
          <label className="grid gap-2 text-sm">
            <span className="font-medium">姓名</span>
            <Input defaultValue={account.name} name="name" required />
          </label>
          <label className="grid gap-2 text-sm">
            <span className="font-medium">头像 URL</span>
            <Input defaultValue={account.avatarUrl} name="avatarUrl" placeholder="https://example.com/avatar.png" type="url" />
          </label>
          <label className="grid gap-2 text-sm">
            <span className="font-medium">状态</span>
            <Select
              aria-label="账号状态"
              defaultValue={account.status}
              disabled={isCurrentAccount}
              name="status"
              options={[
                { value: "active", label: "启用" },
                { value: "disabled", label: "停用" },
              ]}
            />
          </label>
          <div className="grid gap-3 md:grid-cols-2">
            <label className="grid gap-2 text-sm">
              <span className="font-medium">机构</span>
              <Select
                aria-label="账号机构"
                name="organizationId"
                onValueChange={setSelectedOrganizationId}
                options={[
                  { value: "", label: "选择机构", disabled: true },
                  ...organizations.map((organization) => ({ value: organization.id, label: organization.name })),
                ]}
                value={selectedOrganizationId}
              />
            </label>
            <label className="grid gap-2 text-sm">
              <span className="font-medium">角色</span>
              <Select
                aria-label="账号角色"
                defaultValue={defaultRoleId}
                disabled={organizationRoles.length === 0}
                key={selectedOrganizationId}
                name="roleId"
                options={[
                  { value: "", label: selectedOrganizationId ? "选择角色" : "先选择机构", disabled: true },
                  ...organizationRoles.map((role) => ({ value: role.id, label: role.label })),
                ]}
              />
            </label>
          </div>
          {message ? (
            <p className="rounded-md bg-secondary px-3 py-2 text-sm text-secondary-foreground" role="status">
              {message}
            </p>
          ) : null}
          <div className="flex justify-end gap-2">
            <Button onClick={() => setIsEditOpen(false)} type="button" variant="outline">
              取消
            </Button>
            <Button disabled={isPending} type="submit">
              保存
            </Button>
          </div>
        </form>
      </Dialog>
    </div>
  );
}
