"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 type { ApiResult } from "@/modules/core/server/api";
import type { JoinRequest, Organization, PublicAccount, RoleDefinition } from "@/modules/core/types";

type UserManagementClientProps = {
  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);
}

function getDefaultOrganizationId(organizations: Organization[]): string {
  return organizations[0]?.id ?? "";
}

export function UserManagementClient({
  organizations,
  roles,
  joinRequests,
}: UserManagementClientProps): React.ReactElement {
  const router = useRouter();
  const [selectedOrganizationId, setSelectedOrganizationId] = useState(() => getDefaultOrganizationId(organizations));
  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");

  async function handleCreateAccount(event: FormEvent<HTMLFormElement>): Promise<void> {
    event.preventDefault();
    setMessage("");
    setIsPending(true);

    const formData = new FormData(event.currentTarget);
    const response = await fetch("/api/settings/accounts", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        organizationId: String(formData.get("organizationId") ?? ""),
        roleId: String(formData.get("roleId") ?? ""),
        name: String(formData.get("name") ?? ""),
        email: String(formData.get("email") ?? ""),
        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);
    event.currentTarget.reset();
    router.refresh();
  }

  async function reviewJoinRequest(requestId: string, decision: "approved" | "rejected", roleId: string): Promise<void> {
    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>
          <CardTitle>创建机构用户</CardTitle>
          <CardDescription>管理员创建账号后立即分配到机构和角色。</CardDescription>
        </CardHeader>
        <CardContent>
          <form className="grid gap-3" onSubmit={handleCreateAccount}>
            <label className="grid gap-2 text-sm">
              <span className="font-medium">机构</span>
              <select
                className="h-11 w-full rounded-md border bg-background px-3 text-sm outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring"
                name="organizationId"
                onChange={(event) => setSelectedOrganizationId(event.target.value)}
                value={selectedOrganizationId}
              >
                {organizations.map((organization) => (
                  <option key={organization.id} value={organization.id}>
                    {organization.name}
                  </option>
                ))}
              </select>
            </label>

            <label className="grid gap-2 text-sm">
              <span className="font-medium">角色</span>
              <select
                className="h-11 w-full rounded-md border bg-background px-3 text-sm outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring"
                name="roleId"
                required
              >
                {organizationRoles.map((role) => (
                  <option key={role.id} value={role.id}>
                    {role.label}
                  </option>
                ))}
              </select>
            </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">初始密码</span>
              <Input minLength={6} name="password" required type="password" />
            </label>

            <Button disabled={isPending || organizationRoles.length === 0} type="submit">
              <Plus className="size-4" aria-hidden="true" />
              创建用户
            </Button>
          </form>
          {message ? (
            <p className="mt-3 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 defaultRoleId = requestRoles.find((role) => role.key === "caregiver")?.id ?? requestRoles[0]?.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
                    className="h-10 w-full rounded-md border bg-background px-3 text-sm outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring"
                    defaultValue={defaultRoleId}
                    id={`role-${request.id}`}
                  >
                    {requestRoles.map((role) => (
                      <option key={role.id} value={role.id}>
                        {role.label}
                      </option>
                    ))}
                  </select>
                  <Button
                    disabled={isPending || !defaultRoleId}
                    onClick={() => {
                      const element = document.getElementById(`role-${request.id}`);
                      const roleId = element instanceof HTMLSelectElement ? element.value : defaultRoleId;
                      void reviewJoinRequest(request.id, "approved", roleId);
                    }}
                    size="sm"
                    type="button"
                  >
                    <Check className="size-4" aria-hidden="true" />
                    通过
                  </Button>
                  <Button
                    disabled={isPending}
                    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>
    </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 ?? getDefaultOrganizationId(organizations),
  );
  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 ?? organizationRoles[0]?.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") ?? ""),
      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">状态</span>
            <select
              className="h-11 w-full rounded-md border bg-background px-3 text-sm outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring"
              defaultValue={account.status}
              disabled={isCurrentAccount}
              name="status"
            >
              <option value="active">启用</option>
              <option value="disabled">停用</option>
            </select>
          </label>
          <div className="grid gap-3 md:grid-cols-2">
            <label className="grid gap-2 text-sm">
              <span className="font-medium">机构</span>
              <select
                className="h-11 w-full rounded-md border bg-background px-3 text-sm outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring"
                name="organizationId"
                onChange={(event) => setSelectedOrganizationId(event.target.value)}
                value={selectedOrganizationId}
              >
                {organizations.map((organization) => (
                  <option key={organization.id} value={organization.id}>
                    {organization.name}
                  </option>
                ))}
              </select>
            </label>
            <label className="grid gap-2 text-sm">
              <span className="font-medium">角色</span>
              <select
                className="h-11 w-full rounded-md border bg-background px-3 text-sm outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring"
                defaultValue={defaultRoleId}
                disabled={organizationRoles.length === 0}
                key={selectedOrganizationId}
                name="roleId"
              >
                {organizationRoles.map((role) => (
                  <option key={role.id} value={role.id}>
                    {role.label}
                  </option>
                ))}
              </select>
            </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>
  );
}
