"use client";

import type { FormEvent, ReactNode } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { useMemo, useState, useTransition, useEffect } from "react";

import { getApiBaseUrl } from "@/lib/api";
import type { FortuneGender, FortuneResponse } from "@/lib/fortune";
import {
  flushTelemetryQueue,
  isSoftLaunchClientEnabled,
  queueSoftLaunchTelemetry,
} from "@/lib/soft-launch-client";
import { TUVI_FUNNEL_EVENT, queueTuViFunnelTelemetry } from "@/lib/tuvi-funnel-telemetry.v1";
import { getAccessToken } from "@/lib/web-auth-client";
import {
  buildTuViFortuneApiBody,
  leapMonthInLunarYear,
  TUVI_BIRTH_YEAR_MAX,
  TUVI_BIRTH_YEAR_MIN,
  TUVI_NAME_MAX_LEN,
  type TuViDateInputMode,
  validateTuViClientFields,
} from "@/lib/tuvi-input";
import { pickTuViLaSoHousesPayload, resolveTuViHousesForUi } from "@/lib/tuvi-result-types";
import {
  TUVI_RESULT_KEY,
  type CtkpInterpretPrepV1,
  type TuViHistorySnapshotMetaV1,
  type TuViStoredPayload,
} from "@/lib/tuvi";

function FormSection({
  id,
  title,
  titleAside,
  children,
}: {
  id: string;
  title: string;
  titleAside?: ReactNode;
  children: ReactNode;
}) {
  return (
    <section aria-labelledby={id} className="space-y-3">
      <div>
        <div className="flex flex-wrap items-center gap-2">
          <h2 id={id} className="ctkp-form-section-label text-[15px] leading-tight">
            {title}
          </h2>
          {titleAside}
        </div>
        <div className="ctkp-form-section-rule mt-1.5" aria-hidden />
      </div>
      {children}
    </section>
  );
}

/** Hover/focus native tooltip for condensed labels (full text in aria-label + title). */
function FieldInfoTip({ label }: { label: string }) {
  return (
    <button
      type="button"
      className="inline-flex h-5 min-h-[20px] min-w-[20px] shrink-0 cursor-help items-center justify-center rounded-full border border-[color:var(--ctkp-border-gold)]/80 bg-[color:var(--ctkp-ink-deep)]/60 font-sans text-[11px] font-semibold leading-none text-[color:var(--ctkp-text-secondary)]/90 transition-colors hover:border-[color:var(--ctkp-gold-bright)]/45 hover:text-[color:var(--ctkp-text-main)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--ctkp-gold-bright)]/40"
      title={label}
      aria-label={label}
    >
      ?
    </button>
  );
}

export function TuViForm() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const [isPending, startTransition] = useTransition();
  const [name, setName] = useState("");
  const [dateMode, setDateMode] = useState<TuViDateInputMode>("solar");
  const [birthDate, setBirthDate] = useState("");
  const [lunarYearStr, setLunarYearStr] = useState("");
  const [lunarMonthStr, setLunarMonthStr] = useState("");
  const [lunarDayStr, setLunarDayStr] = useState("");
  const [lunarLeap, setLunarLeap] = useState(false);
  const [birthTime, setBirthTime] = useState("");
  const [viewingYearSolar, setViewingYearSolar] = useState(() => new Date().getFullYear());
  const [gender, setGender] = useState<FortuneGender>("other");
  const [error, setError] = useState<string | null>(null);
  const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
  const [busy, setBusy] = useState(false);
  const blocked = busy || isPending;

  useEffect(() => {
    const raw = searchParams.get("namXem") ?? searchParams.get("viewingYear");
    if (!raw?.trim()) return;
    const y = Math.trunc(Number(raw));
    if (!Number.isFinite(y) || y < TUVI_BIRTH_YEAR_MIN || y > TUVI_BIRTH_YEAR_MAX) return;
    setViewingYearSolar(y);
  }, [searchParams]);

  useEffect(() => {
    if (!isSoftLaunchClientEnabled()) return;
    queueTuViFunnelTelemetry({
      eventType: TUVI_FUNNEL_EVENT.form_view,
      payload: {
        path: "/tu-vi",
        viewingYearSolar,
        hasAccount: Boolean(getAccessToken()),
      },
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps -- mount-only funnel impression
  }, []);

  const lunarYearNum = useMemo(() => {
    const n = parseInt(lunarYearStr, 10);
    return Number.isFinite(n) ? n : NaN;
  }, [lunarYearStr]);

  const leapForSelectedYear = useMemo(() => {
    if (!Number.isFinite(lunarYearNum) || lunarYearNum < TUVI_BIRTH_YEAR_MIN || lunarYearNum > TUVI_BIRTH_YEAR_MAX) {
      return 0;
    }
    return leapMonthInLunarYear(lunarYearNum);
  }, [lunarYearNum]);

  const lunarMonthNum = useMemo(() => {
    const n = parseInt(lunarMonthStr, 10);
    return Number.isFinite(n) ? n : NaN;
  }, [lunarMonthStr]);

  const canOfferLeapToggle =
    dateMode === "lunar" && leapForSelectedYear > 0 && lunarMonthNum === leapForSelectedYear;

  async function onSubmit(e: FormEvent) {
    e.preventDefault();
    if (blocked) return;
    setError(null);
    const fe = validateTuViClientFields({
      dateMode,
      name,
      birthDate,
      birthTime,
      gender,
      lunarYearStr,
      lunarMonthStr,
      lunarDayStr,
      lunarLeap: canOfferLeapToggle ? lunarLeap : false,
      viewingYearSolar,
    });
    setFieldErrors(fe);
    if (Object.keys(fe).length > 0) return;

    const body = buildTuViFortuneApiBody({
      dateMode,
      name,
      birthDate,
      birthTime,
      gender,
      lunarYearStr,
      lunarMonthStr,
      lunarDayStr,
      lunarLeap: canOfferLeapToggle ? lunarLeap : false,
      viewingYearSolar,
    });
    const calendarModeSent: "solar" | "lunar" = dateMode === "lunar" ? "lunar" : "solar";

    const base = getApiBaseUrl();
    if (!base) {
      setError("Chưa kết nối được máy chủ — kiểm tra cấu hình triển khai (URL API) rồi thử lại.");
      return;
    }

    setBusy(true);
    try {
      const res = await fetch(`${base}/fortune/tu-vi`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });
      const data = (await res.json().catch(() => ({}))) as {
        message?: string | string[];
        id?: string;
        receivedAt?: string;
        subject?: FortuneResponse["subject"];
        ctkp_interpret_prep?: unknown;
        reading?: TuViStoredPayload["result"]["reading"];
        ctkp_history_warning_v1?: TuViStoredPayload["ctkp_history_warning_v1"];
      };
      if (!res.ok) {
        const msg = Array.isArray(data.message)
          ? data.message.join(", ")
          : typeof data.message === "string"
            ? data.message
            : `Lỗi ${res.status}`;
        setError(msg);
        return;
      }
      if (
        !data.id ||
        !data.receivedAt ||
        !data.subject ||
        !data.reading ||
        typeof data.subject.name !== "string" ||
        typeof data.subject.birthDate !== "string" ||
        typeof data.subject.birthTime !== "string" ||
        typeof data.subject.gender !== "string"
      ) {
        setError("API trả về dữ liệu không đọc được. Hãy thử lại sau.");
        return;
      }
      const prep =
        data.ctkp_interpret_prep &&
        typeof data.ctkp_interpret_prep === "object" &&
        (data.ctkp_interpret_prep as CtkpInterpretPrepV1).v === 1
          ? (data.ctkp_interpret_prep as CtkpInterpretPrepV1)
          : undefined;
      const rawTop = data as Record<string, unknown>;
      const snapRaw = rawTop.tuvi_history_snapshot_v1;
      const tuvi_history_snapshot_v1 =
        snapRaw &&
        typeof snapRaw === "object" &&
        !Array.isArray(snapRaw) &&
        (snapRaw as TuViHistorySnapshotMetaV1).v === 1
          ? (snapRaw as TuViHistorySnapshotMetaV1)
          : undefined;
      const calendarMode = data.subject.calendarMode ?? calendarModeSent;
      const laSoHouses = pickTuViLaSoHousesPayload({
        tu_vi_la_so_houses: rawTop.tu_vi_la_so_houses,
        ctkp_tuvi_response_v1: rawTop.ctkp_tuvi_response_v1,
      });
      let result: FortuneResponse = {
        id: data.id,
        receivedAt: data.receivedAt,
        subject: {
          name: data.subject.name,
          birthDate: data.subject.birthDate,
          birthTime: data.subject.birthTime,
          gender: data.subject.gender as FortuneGender,
          calendarMode,
          ...(data.subject.lunarBirth ? { lunarBirth: data.subject.lunarBirth } : {}),
        },
        reading: data.reading,
        ...(rawTop.tu_vi_foundation != null ? { tu_vi_foundation: rawTop.tu_vi_foundation } : {}),
        ...(laSoHouses != null ? { tu_vi_la_so_houses: laSoHouses } : {}),
        ...(rawTop.tu_vi_db_lookup != null ? { tu_vi_db_lookup: rawTop.tu_vi_db_lookup } : {}),
        ...(rawTop.chartPlaceholder != null ? { chartPlaceholder: rawTop.chartPlaceholder } : {}),
        ...(rawTop.ctkp_tuvi_response_v1 != null ? { ctkp_tuvi_response_v1: rawTop.ctkp_tuvi_response_v1 } : {}),
        ...(rawTop.tu_vi_chart_artifact_v1 != null ?
          { tu_vi_chart_artifact_v1: rawTop.tu_vi_chart_artifact_v1 }
        : {}),
        ...(rawTop.placedByBranch != null ?
          { placedByBranch: rawTop.placedByBranch as FortuneResponse["placedByBranch"] }
        : {}),
        ...(typeof rawTop.majorStarEngineMode === "string" ?
          { majorStarEngineMode: rawTop.majorStarEngineMode }
        : {}),
        ...(rawTop.interpretationContext != null ?
          { interpretationContext: rawTop.interpretationContext as FortuneResponse["interpretationContext"] }
        : {}),
        ...(rawTop.interpretationProse != null ?
          { interpretationProse: rawTop.interpretationProse as FortuneResponse["interpretationProse"] }
        : {}),
        ...(rawTop.majorPeriodProse != null ?
          { majorPeriodProse: rawTop.majorPeriodProse as FortuneResponse["majorPeriodProse"] }
        : {}),
        ...(rawTop.annualPeriodProse != null ?
          { annualPeriodProse: rawTop.annualPeriodProse as FortuneResponse["annualPeriodProse"] }
        : {}),
        ...(rawTop.monthlyPeriodProse != null ?
          { monthlyPeriodProse: rawTop.monthlyPeriodProse as FortuneResponse["monthlyPeriodProse"] }
        : {}),
        ...(rawTop.dailyPeriodProse != null ?
          { dailyPeriodProse: rawTop.dailyPeriodProse as FortuneResponse["dailyPeriodProse"] }
        : {}),
        ...(rawTop.insightProse != null ?
          { insightProse: rawTop.insightProse as FortuneResponse["insightProse"] }
        : {}),
        ...(rawTop.personalizedAdvice != null ?
          { personalizedAdvice: rawTop.personalizedAdvice as FortuneResponse["personalizedAdvice"] }
        : {}),
        ...(rawTop.interpretationDebug != null ?
          { interpretationDebug: rawTop.interpretationDebug as FortuneResponse["interpretationDebug"] }
        : {}),
        ...(rawTop.ctkp_generation_partial_v1 != null &&
        typeof rawTop.ctkp_generation_partial_v1 === "object" &&
        !Array.isArray(rawTop.ctkp_generation_partial_v1) &&
        typeof (rawTop.ctkp_generation_partial_v1 as { message_vi?: unknown }).message_vi === "string" ?
          {
            ctkp_generation_partial_v1: rawTop.ctkp_generation_partial_v1 as NonNullable<
              FortuneResponse["ctkp_generation_partial_v1"]
            >,
          }
        : {}),
      };
      const forUi = resolveTuViHousesForUi(result);
      if (forUi) {
        result = { ...result, tu_vi_la_so_houses: forUi };
      }
      const payload: TuViStoredPayload = {
        snapshot_v: tuvi_history_snapshot_v1 ? 2 : 1,
        ...(tuvi_history_snapshot_v1 ? { tuvi_history_snapshot_v1 } : {}),
        result,
        calendarMode,
        source: "api",
        tu_vi_api_request_v1: {
          majorStarEngineMode: String(body.majorStarEngineMode ?? ""),
          ...(typeof body.tuViChartRulesetV1 === "string" ?
            { tuViChartRulesetV1: body.tuViChartRulesetV1 }
          : {}),
        },
        ...(prep ? { ctkp_interpret_prep: prep } : {}),
        ...(data.ctkp_history_warning_v1 ? { ctkp_history_warning_v1: data.ctkp_history_warning_v1 } : {}),
      };
      if (typeof sessionStorage !== "undefined") {
        try {
          sessionStorage.setItem(TUVI_RESULT_KEY, JSON.stringify(payload));
        } catch {
          setError(
            "Đã nhận kết quả từ máy chủ nhưng không lưu được trên trình duyệt (hết dung lượng, profile hạn chế, hoặc chế độ riêng tư). Hãy thử tab thường, giải phóng dung lượng, rồi gửi lại — hoặc mở nhật ký nếu máy chủ đã lưu được.",
          );
          return;
        }
      }
      if (isSoftLaunchClientEnabled()) {
        queueTuViFunnelTelemetry({
          chartId: data.id,
          eventType: TUVI_FUNNEL_EVENT.form_submit,
          payload: {
            path: "/tu-vi",
            viewingYearSolar,
            hasAccount: Boolean(getAccessToken()),
            source: "api",
          },
        });
        queueSoftLaunchTelemetry({ chartId: data.id, eventType: "chart_generation_complete" });
        void flushTelemetryQueue();
      }
      startTransition(() => {
        router.push("/tu-vi/ket-qua");
      });
    } catch {
      setError(
        "Không kết nối được máy chủ hoặc lỗi mạng — hãy chạy backend nếu đang phát triển cục bộ, kiểm tra cấu hình triển khai, rồi thử lại.",
      );
    } finally {
      setBusy(false);
    }
  }

  const labelClass =
    "font-ctkp-display text-[14px] font-medium leading-tight text-[color:var(--ctkp-text-main)]";
  const hintClass = "font-sans text-[12px] leading-snug text-[color:var(--ctkp-text-secondary)]/90";
  const fieldBlockClass = "space-y-1.5";
  const inputBase =
    "font-sans mt-0 rounded-[9px] border border-[color:var(--ctkp-border-gold-strong)] bg-[color:var(--ctkp-ink-raised)]/85 px-3 py-2 text-[14px] text-[color:var(--ctkp-text-main)] shadow-[inset_0_1px_8px_rgba(0,0,0,0.32)] outline-none transition-[border-color,box-shadow,background-color] duration-300 ease-ctkp placeholder:text-[color:var(--ctkp-text-secondary)]/45 focus:border-[color:var(--ctkp-gold-bright)]/55 focus:bg-[color:var(--ctkp-ink-raised)] focus:shadow-[inset_0_1px_8px_rgba(0,0,0,0.26),0_0_0_1px_var(--ctkp-glow-gold-soft),0_0_16px_-4px_var(--ctkp-glow-gold-soft)]";
  const inputClass = `${inputBase} w-full`;
  const inputClassCompact = `${inputBase} w-full max-w-[13rem] sm:max-w-[12.5rem]`;
  const errClass = "font-sans text-[12px] leading-snug text-red-300/95";

  return (
    <div className="relative pt-2">
      <div className="pointer-events-none absolute inset-0 -top-6 flex justify-center opacity-[0.07]" aria-hidden>
        <div className="h-40 w-[min(100%,28rem)] bg-[radial-gradient(ellipse_at_center,rgba(201,161,93,0.5),transparent_70%)] blur-2xl" />
      </div>

      <div className="ctkp-mystic-card relative isolate">
        <span
          className="pointer-events-none absolute left-[18px] top-[18px] z-[2] h-5 w-5 border-l border-t border-[color:var(--ctkp-gold-bright)]/25"
          aria-hidden
        />
        <span
          className="pointer-events-none absolute right-[18px] top-[18px] z-[2] h-5 w-5 border-r border-t border-[color:var(--ctkp-gold-bright)]/25"
          aria-hidden
        />
        <span
          className="pointer-events-none absolute bottom-[18px] left-[18px] z-[2] h-5 w-5 border-b border-l border-[color:var(--ctkp-gold-bright)]/25"
          aria-hidden
        />
        <span
          className="pointer-events-none absolute bottom-[18px] right-[18px] z-[2] h-5 w-5 border-b border-r border-[color:var(--ctkp-gold-bright)]/25"
          aria-hidden
        />

        <form
          onSubmit={onSubmit}
          aria-busy={blocked}
          inert={blocked ? true : undefined}
          className={`relative z-[1] space-y-5 rounded-[inherit] p-5 font-sans sm:space-y-6 sm:p-6 ${
            blocked ? "pointer-events-none opacity-[0.72]" : ""
          }`}
          noValidate
        >
          <div className="flex gap-3 border-b border-[color:var(--ctkp-border-gold)] pb-4 sm:items-start sm:gap-3.5">
            <span
              className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full border border-[color:var(--ctkp-border-gold-strong)] bg-[color:var(--ctkp-ink-deep)] font-ctkp-display text-base text-[color:var(--ctkp-gold-bright)]/55"
              aria-hidden
            >
              ☽
            </span>
            <div className="min-w-0">
              <div className="flex flex-wrap items-center gap-2">
                <p className="font-ctkp-display text-[1rem] font-semibold leading-tight text-[color:var(--ctkp-text-main)]">
                  Thông tin mở lá số
                </p>
                <FieldInfoTip label="Ô có dấu * là bắt buộc. Chọn lịch bạn tin nhất — dương theo giấy tờ, âm theo lịch nhà (có nhuận). Cùng mốc âm + cùng giờ cho cùng một lá." />
              </div>
              <p className={`mt-1 max-w-prose ${hintClass}`}>
                <span className="text-[color:var(--ctkp-gold-bright)]/85">*</span> bắt buộc · Dương/Âm tùy nguồn bạn chọn.
              </p>
            </div>
          </div>

          <div className="grid grid-cols-1 gap-5 md:grid-cols-2 md:gap-5 md:items-start">
            <FormSection id="tuvi-sec-person" title="Thông tin cơ bản">
              <div className={fieldBlockClass}>
                <div className="flex flex-wrap items-center gap-2">
                  <label htmlFor="tuvi-name" className={labelClass}>
                    Họ tên <span className="text-[color:var(--ctkp-gold-bright)]/78">*</span>
                  </label>
                  <FieldInfoTip label="Tên đầy đủ hay tên thường gọi — dùng trên lá số." />
                </div>
                <input
                  id="tuvi-name"
                  name="name"
                  maxLength={TUVI_NAME_MAX_LEN}
                  value={name}
                  onChange={(e) => {
                    setName(e.target.value);
                    if (fieldErrors.name) setFieldErrors((f) => ({ ...f, name: "" }));
                  }}
                  autoComplete="name"
                  aria-invalid={!!fieldErrors.name}
                  aria-describedby={
                    [fieldErrors.name ? "tuvi-name-err" : ""].filter(Boolean).join(" ") || undefined
                  }
                  className={inputClass}
                  placeholder="Nguyễn Văn A"
                />
                {fieldErrors.name ? (
                  <p id="tuvi-name-err" className={`${errClass} mt-0.5`} role="alert">
                    {fieldErrors.name}
                  </p>
                ) : null}
              </div>

              <div className={`${fieldBlockClass} pt-0.5`}>
                <div className="flex flex-wrap items-center gap-2">
                  <span id="tuvi-gender-label" className={labelClass}>
                    Giới tính <span className="text-[color:var(--ctkp-gold-bright)]/78">*</span>
                  </span>
                  <FieldInfoTip label="Dùng trong luận giải; chọn mục gần nhất với bản thân." />
                </div>
                <div
                  className="mt-1.5 flex flex-wrap gap-2 text-[13px] text-[color:var(--ctkp-text-main)]"
                  role="group"
                  aria-labelledby="tuvi-gender-label"
                >
                  {(
                    [
                      ["male", "Nam"],
                      ["female", "Nữ"],
                      ["other", "Khác"],
                    ] as const
                  ).map(([value, lbl]) => (
                    <label
                      key={value}
                      className="flex cursor-pointer items-center gap-2 rounded-[8px] border border-[color:var(--ctkp-border-gold)] bg-[color:var(--ctkp-ink-deep)]/80 px-2.5 py-1.5 transition-[border-color,background-color] duration-300 ease-ctkp hover:border-[color:var(--ctkp-gold-bright)]/40"
                    >
                      <input
                        type="radio"
                        name="gender"
                        value={value}
                        checked={gender === value}
                        onChange={() => setGender(value)}
                        className="border-[color:var(--ctkp-border-gold-strong)] bg-[color:var(--ctkp-ink-raised)] text-[color:var(--ctkp-seal-deep)] focus:ring-[color:var(--ctkp-gold-muted)]/35"
                      />
                      {lbl}
                    </label>
                  ))}
                </div>
              </div>
            </FormSection>

            <FormSection
              id="tuvi-sec-birth"
              title="Ngày giờ sinh"
              titleAside={
                <FieldInfoTip label="Dương: ngày theo lịch dương. Âm: năm·tháng·ngày theo lịch nhà. Giờ luôn 24h." />
              }
            >
              <div className={fieldBlockClass}>
                <div className="flex flex-wrap items-center gap-2">
                  <span id="tuvi-date-mode-label" className={labelClass}>
                    Loại lịch
                  </span>
                </div>
                <p id="tuvi-date-mode-hint" className="sr-only">
                  Chọn dương lịch hoặc âm lịch (có hỗ trợ nhuận) cho ngày sinh.
                </p>
                <div
                  className="ctkp-segmented mt-1.5 w-full min-w-0"
                  role="group"
                  aria-labelledby="tuvi-date-mode-label"
                  aria-describedby="tuvi-date-mode-hint"
                >
                  <button
                    type="button"
                    onClick={() => {
                      setDateMode("solar");
                      setFieldErrors((f) => {
                        const n = { ...f };
                        delete n.lunarYear;
                        delete n.lunarMonth;
                        delete n.lunarDay;
                        delete n.lunarLeap;
                        return n;
                      });
                    }}
                    className={`ctkp-segmented-btn ${dateMode === "solar" ? "ctkp-segmented-btn--on" : "ctkp-segmented-btn--off"}`}
                  >
                    Dương lịch
                  </button>
                  <button
                    type="button"
                    onClick={() => {
                      setDateMode("lunar");
                      setFieldErrors((f) => {
                        const n = { ...f };
                        delete n.birthDate;
                        return n;
                      });
                    }}
                    className={`ctkp-segmented-btn ${dateMode === "lunar" ? "ctkp-segmented-btn--on" : "ctkp-segmented-btn--off"}`}
                  >
                    Âm lịch
                  </button>
                </div>
              </div>

              {dateMode === "solar" ? (
                <div className="mt-1 flex flex-col gap-3 sm:flex-row sm:items-end sm:gap-4">
                  <div className="min-w-0 flex-1 space-y-1.5">
                    <div className="flex flex-wrap items-center gap-1.5">
                      <label htmlFor="tuvi-birth-date" className={labelClass}>
                        Ngày sinh <span className="text-[color:var(--ctkp-gold-bright)]/78">*</span>
                      </label>
                      <FieldInfoTip label="Chọn ngày dương như giấy khai sinh hoặc hồ sơ bạn tin nhất." />
                    </div>
                    <p id="tuvi-date-hint" className="sr-only">
                      Ngày sinh theo lịch dương
                    </p>
                    <input
                      id="tuvi-birth-date"
                      name="birthDate"
                      type="date"
                      value={birthDate}
                      onChange={(e) => {
                        setBirthDate(e.target.value);
                        if (fieldErrors.birthDate) setFieldErrors((f) => ({ ...f, birthDate: "" }));
                      }}
                      aria-invalid={!!fieldErrors.birthDate}
                      aria-describedby={
                        [fieldErrors.birthDate ? "tuvi-date-err" : "", "tuvi-date-hint"].filter(Boolean).join(" ") ||
                        undefined
                      }
                      className={inputClassCompact}
                    />
                    {fieldErrors.birthDate ? (
                      <p id="tuvi-date-err" className={`${errClass} mt-0.5`} role="alert">
                        {fieldErrors.birthDate}
                      </p>
                    ) : null}
                  </div>
                  <div className="w-full shrink-0 space-y-1.5 sm:max-w-[9.5rem]">
                    <div className="flex flex-wrap items-center gap-1.5">
                      <label htmlFor="tuvi-birth-time" className={labelClass}>
                        Giờ <span className="text-[color:var(--ctkp-gold-bright)]/78">*</span>
                      </label>
                      <FieldInfoTip label="Đồng hồ 24 giờ, cùng quy ước cho cả nhập dương và âm." />
                    </div>
                    <p id="tuvi-time-hint" className="sr-only">
                      Giờ sinh 24 giờ
                    </p>
                    <input
                      id="tuvi-birth-time"
                      name="birthTime"
                      type="time"
                      value={birthTime}
                      onChange={(e) => {
                        setBirthTime(e.target.value);
                        if (fieldErrors.birthTime) setFieldErrors((f) => ({ ...f, birthTime: "" }));
                      }}
                      aria-invalid={!!fieldErrors.birthTime}
                      aria-describedby={
                        [fieldErrors.birthTime ? "tuvi-time-err" : "", "tuvi-time-hint"]
                          .filter(Boolean)
                          .join(" ") || undefined
                      }
                      className={inputClassCompact}
                    />
                    {fieldErrors.birthTime ? (
                      <p id="tuvi-time-err" className={`${errClass} mt-0.5`} role="alert">
                        {fieldErrors.birthTime}
                      </p>
                    ) : null}
                  </div>
                </div>
              ) : (
                <>
                  <div className="mt-1 space-y-3 rounded-[10px] border border-[color:var(--ctkp-border-gold)] bg-[color:var(--ctkp-ink-deep)]/65 px-3 py-3 shadow-[inset_0_1px_0_rgba(255,248,235,0.03)]">
                    <div className="flex flex-wrap items-start gap-2">
                      <p className={`${labelClass} text-[13px]`}>Âm lịch</p>
                      <FieldInfoTip label="Năm·tháng·ngày theo âm. Nhuận chỉ khi năm có nhuận và bạn chọn đúng tháng nhuận; không cần tự quy sang dương trước." />
                    </div>
                    <div className="grid grid-cols-1 gap-3 min-[400px]:grid-cols-3 sm:grid-cols-3">
                      <div className={fieldBlockClass}>
                        <label htmlFor="tuvi-lunar-year" className={labelClass}>
                          Năm <span className="text-[color:var(--ctkp-gold-bright)]/78">*</span>
                        </label>
                        <input
                          id="tuvi-lunar-year"
                          name="lunarYear"
                          type="number"
                          inputMode="numeric"
                          min={TUVI_BIRTH_YEAR_MIN}
                          max={TUVI_BIRTH_YEAR_MAX}
                          value={lunarYearStr}
                          onChange={(e) => {
                            setLunarYearStr(e.target.value);
                            if (fieldErrors.lunarYear) setFieldErrors((f) => ({ ...f, lunarYear: "" }));
                          }}
                          aria-invalid={!!fieldErrors.lunarYear}
                          className={inputClass}
                          placeholder={`${TUVI_BIRTH_YEAR_MIN}–${TUVI_BIRTH_YEAR_MAX}`}
                        />
                        {fieldErrors.lunarYear ? (
                          <p className={`${errClass} mt-0.5`} role="alert">
                            {fieldErrors.lunarYear}
                          </p>
                        ) : null}
                      </div>
                      <div className={fieldBlockClass}>
                        <label htmlFor="tuvi-lunar-month" className={labelClass}>
                          Tháng <span className="text-[color:var(--ctkp-gold-bright)]/78">*</span>
                        </label>
                        <input
                          id="tuvi-lunar-month"
                          name="lunarMonth"
                          type="number"
                          inputMode="numeric"
                          min={1}
                          max={12}
                          value={lunarMonthStr}
                          onChange={(e) => {
                            const v = e.target.value;
                            setLunarMonthStr(v);
                            const m = parseInt(v, 10);
                            if (Number.isFinite(lunarYearNum) && leapForSelectedYear > 0 && m !== leapForSelectedYear) {
                              setLunarLeap(false);
                            }
                            if (fieldErrors.lunarMonth) setFieldErrors((f) => ({ ...f, lunarMonth: "" }));
                          }}
                          aria-invalid={!!fieldErrors.lunarMonth}
                          className={inputClass}
                          placeholder="1–12"
                        />
                        {fieldErrors.lunarMonth ? (
                          <p className={`${errClass} mt-0.5`} role="alert">
                            {fieldErrors.lunarMonth}
                          </p>
                        ) : null}
                      </div>
                      <div className={fieldBlockClass}>
                        <label htmlFor="tuvi-lunar-day" className={labelClass}>
                          Ngày <span className="text-[color:var(--ctkp-gold-bright)]/78">*</span>
                        </label>
                        <input
                          id="tuvi-lunar-day"
                          name="lunarDay"
                          type="number"
                          inputMode="numeric"
                          min={1}
                          max={30}
                          value={lunarDayStr}
                          onChange={(e) => {
                            setLunarDayStr(e.target.value);
                            if (fieldErrors.lunarDay) setFieldErrors((f) => ({ ...f, lunarDay: "" }));
                          }}
                          aria-invalid={!!fieldErrors.lunarDay}
                          className={inputClass}
                          placeholder="1–30"
                        />
                        {fieldErrors.lunarDay ? (
                          <p className={`${errClass} mt-0.5`} role="alert">
                            {fieldErrors.lunarDay}
                          </p>
                        ) : null}
                      </div>
                    </div>
                    {leapForSelectedYear > 0 ? (
                      <p className={hintClass}>
                        Năm {lunarYearNum}: nhuận tháng {leapForSelectedYear}. Bật ô dưới nếu sinh đúng tháng nhuận.
                      </p>
                    ) : Number.isFinite(lunarYearNum) &&
                      lunarYearNum >= TUVI_BIRTH_YEAR_MIN &&
                      lunarYearNum <= TUVI_BIRTH_YEAR_MAX ? (
                      <p className={`${hintClass} opacity-90`}>Năm này không có tháng nhuận trong bảng lịch.</p>
                    ) : null}
                    {canOfferLeapToggle ? (
                      <label className="flex cursor-pointer items-start gap-2 rounded-[8px] border border-[color:var(--ctkp-border-gold)] bg-[color:var(--ctkp-ink-raised)]/50 px-2.5 py-2 text-[12px] text-[color:var(--ctkp-text-main)]">
                        <input
                          type="checkbox"
                          checked={lunarLeap}
                          onChange={(e) => {
                            setLunarLeap(e.target.checked);
                            if (fieldErrors.lunarLeap) setFieldErrors((f) => ({ ...f, lunarLeap: "" }));
                          }}
                          className="mt-0.5 border-[color:var(--ctkp-border-gold-strong)] bg-[color:var(--ctkp-ink-deep)] text-[color:var(--ctkp-seal-deep)] focus:ring-[color:var(--ctkp-gold-muted)]/30"
                        />
                        <span>
                          <span className="font-ctkp-display text-[14px] text-[color:var(--ctkp-text-main)]">
                            Sinh tháng nhuận
                          </span>
                          <FieldInfoTip label={`Tháng nhuận ${leapForSelectedYear} (âm): bật nếu đúng, tắt nếu là tháng thường cùng số.`} />
                        </span>
                      </label>
                    ) : null}
                    {fieldErrors.lunarLeap ? (
                      <p className={errClass} role="alert">
                        {fieldErrors.lunarLeap}
                      </p>
                    ) : null}
                  </div>

                  <div className={`${fieldBlockClass} pt-0.5`}>
                    <div className="flex flex-wrap items-center gap-1.5">
                      <label htmlFor="tuvi-birth-time-lunar" className={labelClass}>
                        Giờ sinh <span className="text-[color:var(--ctkp-gold-bright)]/78">*</span>
                      </label>
                      <FieldInfoTip label="Đồng hồ 24 giờ, cùng quy ước cho cả nhập dương và âm." />
                    </div>
                    <p id="tuvi-time-hint-lunar" className="sr-only">
                      Giờ sinh 24 giờ
                    </p>
                    <input
                      id="tuvi-birth-time-lunar"
                      name="birthTime"
                      type="time"
                      value={birthTime}
                      onChange={(e) => {
                        setBirthTime(e.target.value);
                        if (fieldErrors.birthTime) setFieldErrors((f) => ({ ...f, birthTime: "" }));
                      }}
                      aria-invalid={!!fieldErrors.birthTime}
                      aria-describedby={
                        [fieldErrors.birthTime ? "tuvi-time-err-lunar" : "", "tuvi-time-hint-lunar"]
                          .filter(Boolean)
                          .join(" ") || undefined
                      }
                      className={inputClassCompact}
                    />
                    {fieldErrors.birthTime ? (
                      <p id="tuvi-time-err-lunar" className={`${errClass} mt-0.5`} role="alert">
                        {fieldErrors.birthTime}
                      </p>
                    ) : null}
                  </div>
                </>
              )}
            </FormSection>
          </div>

          <FormSection
            id="tuvi-sec-viewing"
            title="Năm xem"
            titleAside={
              <FieldInfoTip
                label={`Năm dương lịch cho an sao lưu (Thái Tuế lưu, Lộc Tồn lưu, Tứ Hóa lưu…). Mặc định năm hiện tại; chọn ${TUVI_BIRTH_YEAR_MIN}–${TUVI_BIRTH_YEAR_MAX}.`}
              />
            }
          >
            <div className={fieldBlockClass}>
              <div className="flex flex-col gap-2 sm:flex-row sm:items-end sm:gap-4">
                <div className="min-w-0 sm:max-w-[10rem]">
                  <label htmlFor="tuvi-viewing-year" className="mb-1.5 block">
                    <span className={labelClass}>Năm dương</span>
                  </label>
                  <input
                    id="tuvi-viewing-year"
                    name="viewingYearSolar"
                    type="number"
                    inputMode="numeric"
                    min={TUVI_BIRTH_YEAR_MIN}
                    max={TUVI_BIRTH_YEAR_MAX}
                    value={viewingYearSolar}
                    onChange={(e) => {
                      const n = parseInt(e.target.value, 10);
                      setViewingYearSolar((prev) => (Number.isFinite(n) ? n : prev));
                      if (fieldErrors.viewingYearSolar) setFieldErrors((f) => ({ ...f, viewingYearSolar: "" }));
                    }}
                    aria-invalid={!!fieldErrors.viewingYearSolar}
                    aria-describedby={
                      [fieldErrors.viewingYearSolar ? "tuvi-viewing-year-err" : ""].filter(Boolean).join(" ") ||
                      undefined
                    }
                    className={inputClassCompact}
                  />
                </div>
                <p className={`pb-1 ${hintClass} sm:flex-1`}>
                  Mặc định năm nay · {TUVI_BIRTH_YEAR_MIN}–{TUVI_BIRTH_YEAR_MAX}
                </p>
              </div>
              {fieldErrors.viewingYearSolar ? (
                <p id="tuvi-viewing-year-err" className={`${errClass} mt-0.5`} role="alert">
                  {fieldErrors.viewingYearSolar}
                </p>
              ) : null}
            </div>
          </FormSection>

          {error ? (
            <p
              className="rounded-[9px] border border-[color:var(--ctkp-seal)]/50 bg-[color:var(--ctkp-seal)]/14 px-3 py-2.5 font-sans text-[12px] leading-snug text-red-100/95"
              role="alert"
            >
              {error}
            </p>
          ) : null}

          <div className="space-y-2 border-t border-[color:var(--ctkp-border-gold)] pt-5">
            <button
              type="submit"
              disabled={blocked}
              className="ctkp-btn-primary w-full py-2.5 tracking-[0.1em] disabled:cursor-not-allowed disabled:opacity-65"
            >
              {blocked ? "Đang mở lá số…" : "Mở lá số"}
            </button>
            <p className="text-center text-[11px] leading-snug text-[color:var(--ctkp-text-secondary)]/88">
              Lưu tạm trên trình duyệt; nhật ký có thể gắn mã khách vô danh.
            </p>
          </div>
        </form>
      </div>
    </div>
  );
}
