import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import {
  ArrowLeft,
  Building2,
  ClipboardCopy,
  Loader2,
  Plus,
  Save,
  ShieldAlert,
  Trash2,
  X,
} from "lucide-react";
import * as React from "react";
import { useForm } from "react-hook-form";
import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { Button } from "../../components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "../../components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "../../components/ui/dialog";
import { Input } from "../../components/ui/input";
import { Label } from "../../components/ui/label";
import { Switch } from "../../components/ui/switch";
import {
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from "../../components/ui/tabs";
import {
  createUser,
  fetchAllTenants,
  fetchMe,
  fetchTenant,
  type TenantSummary,
  type UserAppointment,
  type UserCreateRequest,
  type UserCreateResponse,
} from "../../lib/adminApi";
import { t } from "../../lib/i18n";
import {
  canManageTenantScopedUsers,
  isSuperAdminRole,
  normalizeAdminRole,
} from "../../lib/roles";
import {
  buildAuthenticatedOrgChartTenantPickerUrl,
  filterNonHanmacFamilyTenants,
  getTenantGradeOptions,
  type OrgChartTenantSelection,
  parseOrgChartTenantSelection,
} from "./orgChartPicker";
import type { UserSchemaField } from "./userSchemaFields";
import { resolvePersonalTenant } from "./utils/personalTenant";

type UserFormValues = UserCreateRequest & {
  metadata: Record<string, unknown> & {
    sub_email?: string[];
  };
};
type UserCategory = "hanmac" | "external" | "personal";

type PickerTarget = { kind: "appointment"; index: number };

type AppointmentDraft = UserAppointment & {
  draftId: string;
};

type AdminFrontTestHooks = {
  selectUserAppointmentTenant?: (
    selection: OrgChartTenantSelection,
    index?: number,
  ) => Promise<void>;
};

function createDraftId() {
  return globalThis.crypto?.randomUUID?.() ?? `appointment-${Date.now()}`;
}

async function resolveTenantSelection(
  selection: OrgChartTenantSelection,
  tenants: TenantSummary[],
) {
  const cached = tenants.find((tenant) => tenant.id === selection.id);
  if (cached) {
    return {
      id: cached.id,
      name: cached.name,
      slug: cached.slug,
    };
  }

  const tenant = await fetchTenant(selection.id);
  return {
    id: tenant.id,
    name: tenant.name,
    slug: tenant.slug,
  };
}

function createEmptyAppointment(): AppointmentDraft {
  return {
    draftId: createDraftId(),
    tenantId: "",
    tenantName: "",
    tenantSlug: "",
    isPrimary: false,
    isOwner: false,
    isAdmin: false,
    isManager: false,
    grade: "",
    jobTitle: "",
    position: "",
  };
}

function UserCreatePage() {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const queryClient = useQueryClient();
  const [error, setError] = React.useState<string | null>(null);
  const [generatedPassword, setGeneratedPassword] = React.useState<
    string | null
  >(null);
  const [createdEmail, setCreatedEmail] = React.useState<string | null>(null);
  const [autoPassword, setAutoPassword] = React.useState(true);
  const [userCategory, setUserCategory] =
    React.useState<UserCategory>("hanmac");
  const [additionalAppointments, setAdditionalAppointments] = React.useState<
    AppointmentDraft[]
  >([]);
  const [pickerTarget, setPickerTarget] = React.useState<PickerTarget | null>(
    null,
  );
  const [isResolvingTenant, setIsResolvingTenant] = React.useState(false);

  const [newSubEmail, setNewSubEmail] = React.useState("");

  const { data: tenantsData } = useQuery({
    queryKey: ["tenants", "all"],
    queryFn: () => fetchAllTenants(),
  });
  const tenants = tenantsData?.items ?? [];

  const { data: profile } = useQuery({
    queryKey: ["me"],
    queryFn: fetchMe,
  });
  const profileRole = normalizeAdminRole(profile?.role);
  const canManageUsers = canManageTenantScopedUsers(profile);

  const {
    register,
    handleSubmit,
    watch,
    setValue,
    formState: { errors },
  } = useForm<UserFormValues>({
    defaultValues: {
      email: "",
      password: "",
      name: "",
      phone: "",
      tenantSlug: searchParams.get("tenantSlug") || "",
      department: "",
      grade: "",
      position: "",
      jobTitle: "",
      role: "user",
      metadata: {
        sub_email: [],
      },
    },
  });

  const currentSubEmails = (watch("metadata.sub_email") as string[]) || [];

  const handleAddSubEmail = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Enter" || e.key === "," || e.key === " ") {
      e.preventDefault();
      const value = newSubEmail.trim().replace(/,/g, "");
      if (value?.includes("@") && !currentSubEmails.includes(value)) {
        setValue("metadata.sub_email", [...currentSubEmails, value], {
          shouldDirty: true,
        });
        setNewSubEmail("");
      }
    }
  };

  const handleRemoveSubEmail = (emailToRemove: string) => {
    setValue(
      "metadata.sub_email",
      currentSubEmails.filter((e) => e !== emailToRemove),
      { shouldDirty: true },
    );
  };

  // Lock company for non-super_admin
  React.useEffect(() => {
    if (profileRole !== "super_admin") {
      const delegatedTenantSlug =
        profile?.tenantSlug || profile?.manageableTenants?.[0]?.slug;
      if (delegatedTenantSlug) {
        setValue("tenantSlug", delegatedTenantSlug);
      }
    }
  }, [profile, profileRole, setValue]);

  const hanmacFamilyTenantId = React.useMemo(() => {
    const envTenantId = import.meta.env.VITE_HANMAC_FAMILY_TENANT_ID;
    if (typeof envTenantId === "string" && envTenantId.trim()) {
      return envTenantId.trim();
    }
    return tenants.find((tenant) => tenant.slug === "hanmac-family")?.id ?? "";
  }, [tenants]);
  const nonHanmacFamilyTenants = React.useMemo(
    () => filterNonHanmacFamilyTenants(tenants, hanmacFamilyTenantId),
    [tenants, hanmacFamilyTenantId],
  );

  const selectedTenantSlug = watch("tenantSlug");
  const personalTenant = React.useMemo(
    () => resolvePersonalTenant(tenants),
    [tenants],
  );
  const selectedTenant =
    userCategory !== "external"
      ? undefined
      : nonHanmacFamilyTenants.find((t) => t.slug === selectedTenantSlug);

  const selectedTenantId = selectedTenant?.id ?? "";

  const { data: tenantDetail } = useQuery({
    queryKey: ["tenant", selectedTenantId],
    queryFn: () => fetchTenant(selectedTenantId),
    enabled: selectedTenantId.length > 0,
  });

  const userSchema: UserSchemaField[] = Array.isArray(
    tenantDetail?.config?.userSchema,
  )
    ? (tenantDetail?.config?.userSchema as UserSchemaField[])
    : [];

  const registerMetadata = (field: UserSchemaField) =>
    register(`metadata.${field.key}` as `metadata.${string}`, {
      required: field.required
        ? t(
            "msg.admin.users.create.form.field_required",
            "{{label}}은(는) 필수입니다.",
            {
              label: field.label || field.key,
            },
          )
        : false,
      pattern: field.validation
        ? {
            value: new RegExp(field.validation),
            message: t(
              "msg.admin.users.create.form.field_invalid",
              "{{label}} 형식이 올바르지 않습니다.",
              { label: field.label || field.key },
            ),
          }
        : undefined,
    });

  const pickerUrl = buildAuthenticatedOrgChartTenantPickerUrl(
    import.meta.env.ORGFRONT_URL,
    {
      tenantId: userCategory === "hanmac" ? hanmacFamilyTenantId : undefined,
    },
  );

  const applyTenantSelection = React.useCallback(
    async (selection: OrgChartTenantSelection, target: PickerTarget) => {
      setIsResolvingTenant(true);
      try {
        const tenant = await resolveTenantSelection(selection, tenants);
        setAdditionalAppointments((current) =>
          current.map((appointment, index) =>
            index === target.index
              ? {
                  ...appointment,
                  tenantId: tenant.id,
                  tenantName: tenant.name,
                  tenantSlug: tenant.slug,
                }
              : appointment,
          ),
        );
        setPickerTarget(null);
      } catch (_) {
        setError(
          t(
            "msg.admin.users.create.tenant_resolve_failed",
            "선택한 테넌트 정보를 불러오지 못했습니다.",
          ),
        );
      } finally {
        setIsResolvingTenant(false);
      }
    },
    [tenants],
  );

  React.useEffect(() => {
    if (!pickerTarget) return;

    const onMessage = (event: MessageEvent) => {
      const selection = parseOrgChartTenantSelection(event.data);
      if (!selection) return;
      void applyTenantSelection(selection, pickerTarget);
    };

    window.addEventListener("message", onMessage);
    return () => window.removeEventListener("message", onMessage);
  }, [applyTenantSelection, pickerTarget]);

  if (typeof window !== "undefined") {
    const testWindow = window as Window &
      typeof globalThis & {
        __adminfrontTestHooks?: AdminFrontTestHooks;
      };
    const hooks = testWindow.__adminfrontTestHooks ?? {};
    hooks.selectUserAppointmentTenant = async (selection, index = 0) => {
      await applyTenantSelection(selection, {
        kind: "appointment",
        index,
      });
    };
    testWindow.__adminfrontTestHooks = hooks;
  }

  const addAppointment = () => {
    setAdditionalAppointments((current) => [
      ...current,
      createEmptyAppointment(),
    ]);
  };

  const updateAppointment = (
    index: number,
    patch: Partial<UserAppointment>,
  ) => {
    setAdditionalAppointments((current) =>
      current.map((appointment, currentIndex) => {
        if (currentIndex === index) {
          return { ...appointment, ...patch };
        }
        if (patch.isPrimary === true) {
          return { ...appointment, isPrimary: false };
        }
        return appointment;
      }),
    );
  };

  const removeAppointment = (index: number) => {
    setAdditionalAppointments((current) =>
      current.filter((_, currentIndex) => currentIndex !== index),
    );
  };

  const handleUserCategoryChange = (value: string) => {
    const nextCategory = value as UserCategory;
    setUserCategory(nextCategory);
    if (nextCategory !== "hanmac") {
      setAdditionalAppointments([]);
    }
  };

  const ensurePersonalTenant = async () => {
    return personalTenant;
  };

  const mutation = useMutation({
    mutationFn: createUser,
    onSuccess: (data: UserCreateResponse) => {
      queryClient.invalidateQueries({ queryKey: ["users"] });
      if (data.initialPassword) {
        setGeneratedPassword(data.initialPassword);
        setCreatedEmail(data.email);
        return;
      }
      navigate("/users");
    },
    onError: (err: AxiosError<{ error?: string }>) => {
      setError(
        err.response?.data?.error ||
          t("msg.admin.users.create.error", "사용자 생성에 실패했습니다."),
      );
    },
  });

  const onSubmit = async (data: UserFormValues) => {
    setError(null);
    setGeneratedPassword(null);
    setCreatedEmail(null);

    const {
      hanmacFamily: _hanmacFamily,
      userType: _userType,
      sub_email: rawSubEmail,
      ...formMetadata
    } = data.metadata ?? {};

    const sub_email = Array.isArray(rawSubEmail) ? rawSubEmail : [];

    const metadata: Record<string, unknown> = {
      ...formMetadata,
      ...(sub_email.length > 0 ? { sub_email } : { sub_email: [] }),
    };

    const payload: UserCreateRequest = {
      email: data.email,
      password: data.password,
      name: data.name,
      phone: data.phone,
      role: data.role,
      metadata,
    };

    if (userCategory === "external") {
      if (!data.tenantSlug) {
        setError(
          t(
            "msg.admin.users.create.external_tenant_required",
            "외부 사용자는 대표소속을 선택해 주세요.",
          ),
        );
        return;
      }
      payload.tenantSlug = data.tenantSlug;
      payload.department = data.department;
      payload.grade = data.grade;
      payload.position = data.position;
      payload.jobTitle = data.jobTitle;
    }

    if (userCategory === "personal") {
      try {
        const tenant = await ensurePersonalTenant();
        payload.tenantSlug = tenant.slug;
        payload.metadata = {
          ...metadata,
          personalTenantId: tenant.id,
        };
      } catch (_) {
        setError(
          t(
            "msg.admin.users.create.personal_tenant_failed",
            "Personal 테넌트를 준비하지 못했습니다.",
          ),
        );
        return;
      }
    }

    if (userCategory === "hanmac") {
      const appointments = additionalAppointments
        .filter((appointment) => appointment.tenantId)
        .map((appointment) => ({
          tenantId: appointment.tenantId,
          tenantSlug: appointment.tenantSlug,
          tenantName: appointment.tenantName,
          isPrimary: appointment.isPrimary === true,
          ...(appointment.isOwner === true ? { isOwner: true } : {}),
          ...(appointment.isAdmin === true ? { isAdmin: true } : {}),
          ...(appointment.isManager === true ? { isManager: true } : {}),
          grade: appointment.grade,
          jobTitle: appointment.jobTitle,
          position: appointment.position,
        }));

      if (appointments.length === 0) {
        setError(
          t(
            "msg.admin.users.create.appointment_required",
            "한맥 가족 구성원은 소속 테넌트를 하나 이상 선택해 주세요.",
          ),
        );
        return;
      }

      const primary = appointments.find((a) => a.isPrimary);
      if (primary) {
        metadata.primaryTenantId = primary.tenantId;
        metadata.primaryTenantSlug = primary.tenantSlug;
        metadata.primaryTenantName = primary.tenantName;
      }

      payload.additionalAppointments = appointments;
      payload.metadata = {
        ...metadata,
        additionalAppointments: appointments,
      };
    }

    if (autoPassword) {
      payload.password = "";
    } else if (!data.password) {
      setError(
        t(
          "msg.admin.users.create.password_required",
          "비밀번호를 입력하거나 자동 생성을 사용해 주세요.",
        ),
      );
      return;
    }

    mutation.mutate(payload);
  };

  const onCopyPassword = async () => {
    if (!generatedPassword) return;
    try {
      await navigator.clipboard.writeText(generatedPassword);
    } catch (_) {
      // ignore
    }
  };

  if (profile && !canManageUsers) {
    return (
      <div className="flex h-[50vh] flex-col items-center justify-center space-y-4">
        <ShieldAlert size={48} className="text-destructive" />
        <h3 className="text-lg font-bold">
          {t("msg.admin.common.forbidden", "이 작업을 수행할 권한이 없습니다.")}
        </h3>
        <Button onClick={() => navigate("/")}>
          {t("ui.common.go_home", "홈으로 이동")}
        </Button>
      </div>
    );
  }

  return (
    <div className="max-w-3xl space-y-8">
      <header className="flex flex-wrap items-center justify-between gap-4">
        <div className="space-y-2">
          <h2 className="text-3xl font-semibold">
            {t("ui.admin.users.create.title", "사용자 추가")}
          </h2>
        </div>
        <Button variant="ghost" asChild>
          <Link to="/users">
            <ArrowLeft size={16} className="mr-2" />
            {t("ui.admin.users.create.back", "목록으로 돌아가기")}
          </Link>
        </Button>
      </header>

      {generatedPassword && (
        <Card>
          <CardHeader>
            <CardTitle>
              {t(
                "ui.admin.users.create.password_generated.title",
                "초기 비밀번호 생성 완료",
              )}
            </CardTitle>
            <CardDescription>
              {createdEmail
                ? t(
                    "msg.admin.users.create.password_generated.with_email",
                    "{{email}} 계정의 초기 비밀번호입니다.",
                    { email: createdEmail },
                  )
                : t(
                    "msg.admin.users.create.password_generated.default",
                    "초기 비밀번호가 생성되었습니다.",
                  )}
            </CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            <div className="flex flex-wrap items-center gap-3 rounded-md border border-dashed px-4 py-3">
              <span className="font-mono text-sm">{generatedPassword}</span>
              <Button size="sm" variant="outline" onClick={onCopyPassword}>
                <ClipboardCopy className="mr-2 h-4 w-4" />
                {t("ui.common.copy", "복사")}
              </Button>
            </div>
            <div className="flex justify-end">
              <Button onClick={() => navigate("/users")}>
                {t("ui.admin.users.create.go_list", "목록으로 이동")}
              </Button>
            </div>
          </CardContent>
        </Card>
      )}

      <Card>
        <CardHeader>
          <CardTitle>
            {t("ui.admin.users.create.account.title", "계정 정보")}
          </CardTitle>
          <CardDescription>
            {t(
              "msg.admin.users.create.account.subtitle",
              "새로운 사용자를 시스템에 등록합니다.",
            )}
          </CardDescription>
        </CardHeader>
        <CardContent>
          <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
            {error && (
              <div className="rounded-md bg-destructive/15 p-3 text-sm text-destructive">
                {error}
              </div>
            )}

            <div className="space-y-2">
              <Label htmlFor="email">
                {t("ui.admin.users.create.form.email", "이메일")}
              </Label>
              <Input
                id="email"
                placeholder={t(
                  "ui.admin.users.create.form.email_placeholder",
                  "user@example.com",
                )}
                {...register("email", {
                  required: t(
                    "msg.admin.users.create.form.email_required",
                    "이메일은 필수입니다.",
                  ),
                })}
              />
              {errors.email && (
                <p className="text-xs text-destructive">
                  {errors.email.message}
                </p>
              )}
            </div>

            <div className="space-y-2">
              <Label
                htmlFor="sub_email_input"
                className="flex items-center gap-2"
              >
                {t("ui.admin.users.create.form.sub_email", "보조 이메일")}
              </Label>
              <div className="flex flex-col gap-2">
                <div className="flex flex-wrap gap-2 mb-1">
                  {currentSubEmails.map((email) => (
                    <div
                      key={email}
                      className="inline-flex items-center gap-1 rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 bg-secondary text-secondary-foreground"
                    >
                      {email}
                      <button
                        type="button"
                        onClick={() => handleRemoveSubEmail(email)}
                        className="text-muted-foreground hover:text-foreground ml-1 rounded-full p-0.5 hover:bg-muted transition-colors"
                      >
                        <X size={12} />
                      </button>
                    </div>
                  ))}
                </div>
                <div className="relative">
                  <Input
                    id="sub_email_input"
                    value={newSubEmail}
                    onChange={(e) => setNewSubEmail(e.target.value)}
                    onKeyDown={handleAddSubEmail}
                    className="pr-20"
                    placeholder={t(
                      "ui.admin.users.create.form.sub_email_placeholder",
                      "추가할 이메일 입력 후 Enter",
                    )}
                  />
                  <Button
                    type="button"
                    variant="ghost"
                    size="sm"
                    className="absolute right-1 top-1 h-8 text-xs font-bold"
                    data-testid="add-sub-email-btn"
                    onClick={() => {
                      const value = newSubEmail.trim().replace(/,/g, "");
                      if (
                        value?.includes("@") &&
                        !currentSubEmails.includes(value)
                      ) {
                        setValue(
                          "metadata.sub_email",
                          [...currentSubEmails, value],
                          { shouldDirty: true },
                        );
                        setNewSubEmail("");
                      }
                    }}
                  >
                    {t("ui.common.add", "추가")}
                  </Button>{" "}
                </div>
                <p className="text-[10px] text-muted-foreground mt-1">
                  * 여러 개 입력 가능. 입력 후 엔터를 눌러 추가하세요.
                </p>
              </div>
            </div>

            <div className="space-y-2">
              <div className="flex items-center justify-between">
                <Label htmlFor="password">
                  {t("ui.admin.users.create.form.password", "비밀번호")}
                </Label>
                <label className="flex items-center gap-2 text-xs text-muted-foreground">
                  <input
                    id="auto-password"
                    name="auto-password"
                    type="checkbox"
                    checked={autoPassword}
                    onChange={(event) => setAutoPassword(event.target.checked)}
                  />
                  {t("ui.admin.users.create.form.auto_password", "자동 생성")}
                </label>
              </div>
              <Input
                id="password"
                type="password"
                placeholder={t(
                  "ui.admin.users.create.form.password_placeholder",
                  "********",
                )}
                disabled={autoPassword}
                {...register("password")}
              />
              <p className="text-xs text-muted-foreground">
                {autoPassword
                  ? t(
                      "msg.admin.users.create.form.password_auto_help",
                      "비워두면 시스템이 초기 비밀번호를 자동 생성합니다.",
                    )
                  : t(
                      "msg.admin.users.create.form.password_manual_help",
                      "초기 비밀번호를 직접 설정합니다.",
                    )}
              </p>
            </div>

            <div className="grid gap-4 md:grid-cols-2">
              <div className="space-y-2">
                <Label htmlFor="name">
                  {t("ui.admin.users.create.form.name", "이름")}
                </Label>
                <Input
                  id="name"
                  placeholder={t(
                    "ui.admin.users.create.form.name_placeholder",
                    "홍길동",
                  )}
                  {...register("name", {
                    required: t(
                      "msg.admin.users.create.form.name_required",
                      "이름은 필수입니다.",
                    ),
                  })}
                />
                {errors.name && (
                  <p className="text-xs text-destructive">
                    {errors.name.message}
                  </p>
                )}
              </div>

              <div className="space-y-2">
                <Label htmlFor="phone">
                  {t("ui.admin.users.create.form.phone", "전화번호")}
                </Label>
                <Input
                  id="phone"
                  placeholder={t(
                    "ui.admin.users.create.form.phone_placeholder",
                    "010-1234-5678",
                  )}
                  {...register("phone")}
                />
              </div>
            </div>

            <div className="space-y-2">
              <Label htmlFor="role">
                {t("ui.admin.users.create.form.role", "역할")}
              </Label>
              <select
                id="role"
                className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
                {...register("role")}
                disabled={!isSuperAdminRole(profile?.role)}
              >
                <option value="super_admin">
                  {t("ui.admin.role.super_admin", "시스템 관리자")}
                </option>
                <option value="user">
                  {t("ui.admin.role.user", "일반 사용자")}
                </option>
              </select>
              <p className="text-xs text-muted-foreground">
                {t(
                  "msg.admin.users.create.form.role_help",
                  "시스템 접근 권한을 결정합니다.",
                )}
              </p>
            </div>

            <Tabs value={userCategory} onValueChange={handleUserCategoryChange}>
              <TabsList className="flex h-auto w-full justify-start rounded-none border-b bg-transparent p-0 text-foreground">
                <TabsTrigger
                  value="hanmac"
                  className="-mb-px rounded-b-none rounded-t-md border border-transparent border-b-border bg-muted/40 px-4 py-2 text-muted-foreground shadow-none data-[state=active]:border-border data-[state=active]:border-b-background data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-none"
                >
                  한맥가족 구성원
                </TabsTrigger>
                <TabsTrigger
                  value="external"
                  className="-mb-px rounded-b-none rounded-t-md border border-transparent border-b-border bg-muted/40 px-4 py-2 text-muted-foreground shadow-none data-[state=active]:border-border data-[state=active]:border-b-background data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-none"
                >
                  외부 기업 회원
                </TabsTrigger>
                <TabsTrigger
                  value="personal"
                  className="-mb-px rounded-b-none rounded-t-md border border-transparent border-b-border bg-muted/40 px-4 py-2 text-muted-foreground shadow-none data-[state=active]:border-border data-[state=active]:border-b-background data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-none"
                >
                  개인 회원
                </TabsTrigger>
              </TabsList>

              <TabsContent value="external" className="mt-4 space-y-4">
                <div className="grid gap-4 md:grid-cols-2">
                  <div className="space-y-2">
                    <Label htmlFor="tenantSlug">대표소속</Label>
                    <select
                      id="tenantSlug"
                      className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
                      {...register("tenantSlug")}
                      disabled={profileRole !== "super_admin"}
                    >
                      {nonHanmacFamilyTenants.map((tenant) => (
                        <option key={tenant.id} value={tenant.slug}>
                          {tenant.name} ({tenant.slug})
                        </option>
                      ))}
                    </select>
                  </div>
                  <div className="space-y-2">
                    <Label htmlFor="department">부서</Label>
                    <Input id="department" {...register("department")} />
                  </div>
                </div>

                <div className="grid gap-4 md:grid-cols-3">
                  <div className="space-y-2">
                    <Label htmlFor="grade">직급</Label>
                    <Input
                      id="grade"
                      placeholder="수석/책임/선임"
                      {...register("grade")}
                    />
                  </div>
                  <div className="space-y-2">
                    <Label htmlFor="position">직책</Label>
                    <Input
                      id="position"
                      placeholder="팀장/센터장"
                      {...register("position")}
                    />
                  </div>
                  <div className="space-y-2">
                    <Label htmlFor="jobTitle">직무</Label>
                    <Input
                      id="jobTitle"
                      placeholder="프론트엔드 개발"
                      {...register("jobTitle")}
                    />
                  </div>
                </div>
              </TabsContent>

              <TabsContent value="hanmac" className="mt-4 space-y-4">
                <div className="space-y-3">
                  <div className="flex items-center justify-between gap-3">
                    <div>
                      <p className="text-sm font-medium">
                        소속별 직급/직책/직무
                      </p>
                      <p className="text-xs text-muted-foreground">
                        테넌트별 조직장 여부, 직급, 직책, 직무를 입력합니다.
                      </p>
                    </div>
                    <Button
                      type="button"
                      variant="outline"
                      size="sm"
                      onClick={addAppointment}
                      data-testid="add-appointment-btn"
                    >
                      <Plus className="mr-2 h-4 w-4" />
                      {t("ui.common.add", "추가")}
                    </Button>
                  </div>

                  {additionalAppointments.map((appointment, index) => (
                    <div
                      key={appointment.draftId}
                      data-testid={`appointment-row-${index}`}
                      className="grid gap-3 rounded-md border p-3 lg:grid-cols-[minmax(280px,1.2fr)_minmax(280px,1fr)_auto] lg:items-end"
                    >
                      <div
                        className="space-y-2"
                        data-testid={`appointment-tenant-owner-line-${index}`}
                      >
                        <Label>소속 테넌트</Label>
                        <div
                          className="flex items-center justify-between gap-3"
                          data-testid={`appointment-tenant-owner-controls-${index}`}
                        >
                          <div className="flex min-w-0 flex-1 items-center gap-3">
                            <Button
                              type="button"
                              variant="outline"
                              className="min-w-0 max-w-full"
                              onClick={() =>
                                setPickerTarget({
                                  kind: "appointment",
                                  index,
                                })
                              }
                              disabled={isResolvingTenant}
                              data-testid={`appointment-tenant-picker-${index}`}
                            >
                              <Building2 className="mr-2 h-4 w-4 shrink-0" />
                              <span className="truncate">
                                {appointment.tenantName || "테넌트 선택"}
                              </span>
                            </Button>
                            {appointment.tenantSlug && (
                              <span className="truncate text-xs text-muted-foreground">
                                {appointment.tenantSlug}
                              </span>
                            )}
                          </div>
                          <div className="flex shrink-0 items-center gap-3 whitespace-nowrap">
                            <label className="flex items-center gap-2 text-sm">
                              <Switch
                                checked={appointment.isPrimary === true}
                                onCheckedChange={(checked) =>
                                  updateAppointment(index, {
                                    isPrimary: checked === true,
                                  })
                                }
                                aria-label={t(
                                  "ui.admin.users.detail.form.appointment_owner",
                                  "대표 조직",
                                )}
                              />
                              {t(
                                "ui.admin.users.detail.form.appointment_owner",
                                "대표 조직",
                              )}
                            </label>
                            <label className="flex items-center gap-2 text-sm">
                              <Switch
                                checked={appointment.isManager === true}
                                onCheckedChange={(checked) =>
                                  updateAppointment(index, {
                                    isManager: checked === true,
                                  })
                                }
                                aria-label={t(
                                  "ui.admin.users.detail.form.appointment_manager",
                                  "조직장",
                                )}
                              />
                              {t(
                                "ui.admin.users.detail.form.appointment_manager",
                                "조직장",
                              )}
                            </label>
                          </div>
                        </div>
                      </div>

                      <div
                        className="grid gap-3 sm:grid-cols-3"
                        data-testid={`appointment-position-line-${index}`}
                      >
                        <div className="space-y-2">
                          <Label htmlFor={`appointment-grade-${index}`}>
                            직급
                          </Label>
                          <select
                            id={`appointment-grade-${index}`}
                            className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
                            value={appointment.grade ?? ""}
                            onChange={(event) =>
                              updateAppointment(index, {
                                grade: event.target.value || "",
                              })
                            }
                          >
                            <option value="">없음</option>
                            {getTenantGradeOptions(appointment, tenants).map(
                              (grade) => (
                                <option key={grade} value={grade}>
                                  {grade}
                                </option>
                              ),
                            )}
                          </select>
                        </div>
                        <div className="space-y-2">
                          <Label htmlFor={`appointment-job-title-${index}`}>
                            직무
                          </Label>
                          <Input
                            id={`appointment-job-title-${index}`}
                            value={appointment.jobTitle ?? ""}
                            onChange={(event) =>
                              updateAppointment(index, {
                                jobTitle: event.target.value,
                              })
                            }
                          />
                        </div>
                        <div className="space-y-2">
                          <Label htmlFor={`appointment-position-${index}`}>
                            직책
                          </Label>
                          <Input
                            id={`appointment-position-${index}`}
                            value={appointment.position ?? ""}
                            onChange={(event) =>
                              updateAppointment(index, {
                                position: event.target.value,
                              })
                            }
                          />
                        </div>
                      </div>
                      <Button
                        type="button"
                        variant="ghost"
                        size="sm"
                        onClick={() => removeAppointment(index)}
                      >
                        <Trash2 className="h-4 w-4" />
                        <span className="sr-only">
                          {t("ui.common.delete", "삭제")}
                        </span>
                      </Button>
                    </div>
                  ))}
                </div>
              </TabsContent>

              <TabsContent value="personal" className="mt-4">
                <div
                  className="rounded-md border bg-muted/30 p-4 text-sm"
                  data-testid="personal-tenant-summary"
                >
                  {personalTenant
                    ? `Personal (${personalTenant.slug})`
                    : "Personal 테넌트로 생성됩니다."}
                </div>
              </TabsContent>
            </Tabs>

            {userSchema.length > 0 && (
              <div className="border-t pt-4">
                <h3 className="mb-4 text-sm font-medium text-muted-foreground">
                  {t(
                    "ui.admin.users.create.custom_fields.title",
                    "테넌트 확장 정보 (Custom Fields)",
                  )}
                </h3>

                <div className="grid gap-4 md:grid-cols-2">
                  {userSchema.map((field) => (
                    <div key={field.key} className="space-y-2">
                      <Label htmlFor={`metadata.${field.key}`}>
                        {field.label}
                        {field.required && (
                          <span className="ml-1 text-destructive">*</span>
                        )}
                        {field.adminOnly && (
                          <span className="ml-2 text-[10px] bg-blue-500/10 text-blue-500 px-1.5 py-0.5 rounded uppercase font-bold tracking-tighter">
                            Admin Only
                          </span>
                        )}
                        {field.isLoginId && (
                          <span className="ml-2 text-[10px] bg-green-500/10 text-green-600 px-1.5 py-0.5 rounded uppercase font-bold">
                            {t(
                              "ui.admin.users.create.form.is_login_id",
                              "로그인 ID",
                            )}
                          </span>
                        )}
                      </Label>

                      <Input
                        id={`metadata.${field.key}`}
                        type={
                          field.type === "number"
                            ? "number"
                            : field.type === "date"
                              ? "date"
                              : field.type === "boolean"
                                ? "checkbox"
                                : "text"
                        }
                        className={
                          field.type === "boolean" ? "w-auto h-auto" : ""
                        }
                        {...registerMetadata(field)}
                      />
                      {errors.metadata?.[field.key] && (
                        <p className="text-xs text-destructive">
                          {
                            (
                              errors.metadata[field.key] as {
                                message?: string;
                              }
                            )?.message
                          }
                        </p>
                      )}
                    </div>
                  ))}
                </div>
              </div>
            )}

            <div className="flex justify-end gap-4">
              <Button
                type="button"
                variant="outline"
                onClick={() => navigate("/users")}
              >
                {t("ui.common.cancel", "취소")}
              </Button>
              <Button type="submit" disabled={mutation.isPending}>
                {mutation.isPending && (
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                )}
                <Save className="mr-2 h-4 w-4" />
                {t("ui.admin.users.create.submit", "사용자 생성")}
              </Button>
            </div>
          </form>
        </CardContent>
      </Card>
      <Dialog
        open={pickerTarget !== null}
        onOpenChange={(open) => {
          if (!open) setPickerTarget(null);
        }}
      >
        <DialogContent className="max-w-[460px] p-4">
          <DialogHeader>
            <DialogTitle>
              {t("ui.admin.users.create.form.pick_tenant", "테넌트 선택")}
            </DialogTitle>
            <DialogDescription>
              {t(
                "msg.admin.users.create.form.picker_description",
                "org-chart에서 테넌트를 선택하면 사용자 소속에 반영됩니다.",
              )}
            </DialogDescription>
          </DialogHeader>
          <iframe
            title={t("ui.admin.users.create.form.pick_tenant", "테넌트 선택")}
            src={pickerUrl}
            className="h-[600px] w-full rounded-md border"
            data-testid="appointment-tenant-picker-frame"
          />
        </DialogContent>
      </Dialog>
    </div>
  );
}

export default UserCreatePage;
