"use client";

import Link from "next/link";
import { useRouter } from "next/navigation";
import {
  useActionState,
  useEffect,
  useState,
  type FormEvent,
  type ReactNode,
} from "react";
import { MailAiAssistPanel } from "@/components/mail-ai-assist-panel";
import { MailAddressBookPanel } from "@/components/mail-address-book-panel";
import { MailAutoClassificationPanel } from "@/components/mail-auto-classification-panel";
import { MailIntegrationsPanel } from "@/components/mail-integrations-panel";
import { MailLanguageSettingsPanel } from "@/components/mail-language-settings-panel";
import { MailSpamSettingsPanel } from "@/components/mail-spam-settings-panel";
import { MailStorageSettingsPanel } from "@/components/mail-storage-settings-panel";
import { MailSignatureSettingsPanel } from "@/components/mail-signature-settings";
import { useI18n } from "@/components/i18n-provider";
import { CloseIconButton } from "@/components/close-icon-button";
import { StaticUiLocalizer } from "@/components/static-ui-localizer";
import {
  MailMembersPanel,
  type MemberMailboxViewState,
} from "@/components/mail-members-panel";
import { TossBillingModule } from "@/components/toss-billing-module";
import { PolarBillingModule } from "@/components/polar-billing-module";
import {
  completeMailSetupAction,
  regenerateMailSetupDkimAction,
  updateMailboxDisplayNameAction,
  updateMailSetupDkimUsageAction,
  updateRepresentativePasswordAction,
  verifyMailSetupAction,
} from "@/app/actions/session";
import { SubmitButton } from "@/components/submit-button";
import { DomainSetupAssistance } from "@/components/domain-setup-assistance";
import {
  countMailBillingSeatsFromManagedMembers,
  type MailPlanSummary,
} from "@/lib/mail-billing";
import type {
  MailBillingHistoryState,
  MailBillingTab,
} from "@/lib/mail-billing-history";
import type { MailBillingCancellationOverview } from "@/lib/billing-cancellation";
import type {
  MailSetupOverview,
} from "@/lib/official-mail";
import type {
  MailAiAssistOverview,
  ManagedMailboxMember,
} from "@/lib/mail-automation";
import type {
  MailBillingHistoryPage,
  MailBillingOverview,
} from "@/lib/toss-pay";
import { OFFICIAL_MAIL_GUIDE_URL } from "@/lib/mail-urls";
import type { MailSignatureSettings } from "@/lib/mail-signature";
import type { MailBillingProvider } from "@/lib/billing-region";
import type { PolarBillingOverview } from "@/lib/polar-billing";
import { trackMarketingFunnelEvent } from "@/lib/marketing-funnel-client";

export type MailSetupSection =
  | "account"
  | "contacts"
  | "classification"
  | "spam"
  | "storage"
  | "domain"
  | "assistant"
  | "integrations"
  | "members"
  | "billing"
  | "language";

type MailSetupWorkspaceProps = {
  section: MailSetupSection;
  dkimRegenerated: boolean;
  overview: MailSetupOverview | null;
  aiAssistOverview: MailAiAssistOverview | null;
  billingOverview: MailBillingOverview | null;
  billingProvider: MailBillingProvider;
  usesTossPayments: boolean;
  polarBillingOverview: PolarBillingOverview | null;
  billingCancellationOverview: MailBillingCancellationOverview | null;
  billingHistoryPage: MailBillingHistoryPage | null;
  billingHistoryState: MailBillingHistoryState;
  billingTab: MailBillingTab;
  managedMembers: ManagedMailboxMember[];
  memberMailboxView: MemberMailboxViewState | null;
  planSummary: MailPlanSummary;
  canManageBilling: boolean;
  domainSetupAssistanceAvailable: boolean;
  sessionCompanyName: string;
  sessionDisplayName: string;
  sessionDomain: string;
  sessionEmail: string;
  sessionNotificationEmail: string;
  sessionRecoveryEmail: string;
  sessionRecoveryEmailVerified: boolean;
  sessionMailbox: string;
  signatureSettings: MailSignatureSettings;
};

type DnsRow = {
  key: string;
  type: string;
  host: string;
  value: string;
  ttl: string;
  priorityValue: string;
  statusLabel: string;
  statusTone: "neutral" | "success" | "warning" | "error";
  copyValue: string;
};

type RepresentativePasswordActionState = {
  status: "idle" | "success" | "error";
  message: string;
};

type MailboxDisplayNameActionState = {
  status: "idle" | "success" | "error";
  message: string;
  displayName?: string;
};

type DkimKeySize = 1024 | 2048;

const DOMAIN_PROVIDERS = [
  { id: "gabia", label: "가비아", hint: "My가비아 · DNS 관리툴" },
  { id: "cafe24", label: "카페24", hint: "나의 서비스 관리 · DNS 관리" },
  { id: "hostingkr", label: "호스팅KR", hint: "도메인 · DNS 레코드 관리" },
  { id: "whois", label: "후이즈", hint: "도메인 활용 · DNS 관리" },
  { id: "cloudflare", label: "Cloudflare", hint: "도메인 · DNS · Records" },
  { id: "godaddy", label: "GoDaddy", hint: "My Products · Manage DNS" },
  { id: "namecheap", label: "Namecheap", hint: "Domain List · Advanced DNS" },
  { id: "imweb", label: "아임웹", hint: "도메인 구매 · 도메인 관리" },
  { id: "firstmall", label: "퍼스트몰", hint: "도메인 구매 · 도메인 관리" },
  { id: "unknown", label: "잘 모르겠어요", hint: "구매 내역부터 함께 찾습니다" },
] as const;

type DomainProviderId = (typeof DOMAIN_PROVIDERS)[number]["id"];

const WEBSITE_HOSTING_PROVIDERS = [
  { id: "imweb", label: "아임웹", hint: "관리자 · 환경설정 · 도메인" },
  { id: "firstmall", label: "퍼스트몰", hint: "관리자 · 설정 · 도메인" },
  { id: "cafe24-shop", label: "카페24 쇼핑몰", hint: "쇼핑몰 관리자 · 도메인 설정" },
  { id: "sixshop", label: "식스샵", hint: "관리자 · 도메인 연결" },
  { id: "makeshop", label: "메이크샵", hint: "관리자 · 도메인 관리" },
  { id: "shopify", label: "Shopify", hint: "Settings · Domains" },
  { id: "wix", label: "Wix", hint: "Domains · Advanced" },
  { id: "wordpress", label: "WordPress.com", hint: "Upgrades · Domains" },
  { id: "cloudflare", label: "Cloudflare", hint: "도메인 · DNS · Records" },
  { id: "vercel", label: "Vercel", hint: "Project · Settings · Domains" },
  { id: "railway", label: "Railway", hint: "Project · Settings · Domains" },
  { id: "other", label: "기타 호스팅사", hint: "홈페이지 관리자에서 DNS 메뉴 찾기" },
  { id: "unknown", label: "잘 모르겠어요", hint: "현재 연결 위치부터 함께 확인합니다" },
] as const;

type WebsiteHostingProviderId = (typeof WEBSITE_HOSTING_PROVIDERS)[number]["id"];
type WebsiteConnectionState = "yes" | "no" | "";

const INITIAL_REPRESENTATIVE_PASSWORD_ACTION_STATE: RepresentativePasswordActionState = {
  status: "idle",
  message: "",
};

const INITIAL_MAILBOX_DISPLAY_NAME_ACTION_STATE: MailboxDisplayNameActionState = {
  status: "idle",
  message: "",
};

const SECTION_TRANSLATION_KEYS = {
  account: {
    description: "settings.account.description",
    label: "settings.account.label",
    title: "settings.account.title",
  },
  classification: {
    description: "settings.classification.description",
    label: "settings.classification.label",
    title: "settings.classification.title",
  },
  contacts: {
    description: "settings.contacts.description",
    label: "settings.contacts.label",
    title: "settings.contacts.title",
  },
  spam: {
    description: "settings.spam.description",
    label: "settings.spam.label",
    title: "settings.spam.title",
  },
  storage: {
    description: "settings.storage.description",
    label: "settings.storage.label",
    title: "settings.storage.title",
  },
  domain: {
    description: "settings.domain.description",
    label: "settings.domain.label",
    title: "settings.domain.title",
  },
  assistant: {
    description: "settings.assistant.description",
    label: "settings.assistant.label",
    title: "settings.assistant.title",
  },
  integrations: {
    description: "settings.integrations.description",
    label: "settings.integrations.label",
    title: "settings.integrations.title",
  },
  members: {
    description: "settings.members.description",
    label: "settings.members.label",
    title: "settings.members.title",
  },
  billing: {
    description: "settings.billing.description",
    label: "settings.billing.label",
    title: "settings.billing.title",
  },
  language: {
    description: "settings.language.description",
    label: "settings.language.label",
    title: "settings.language.title",
  },
} as const;

const SETTINGS_NAV_SECTIONS: MailSetupSection[] = [
  "account",
  "contacts",
  "classification",
  "spam",
  "storage",
  "domain",
  "assistant",
  "integrations",
  "members",
  "billing",
  "language",
];

function buildSettingsProfileInitials(displayName: string, companyName: string, email: string) {
  const source = (displayName || companyName || email.split("@")[0] || "OM")
    .replace(/\s+/g, "")
    .trim();

  if (!source) {
    return "OM";
  }

  return source.slice(0, Math.min(2, source.length)).toUpperCase();
}

function normalizeDomainPreview(value: string) {
  return value
    .trim()
    .toLowerCase()
    .replace(/^https?:\/\//, "")
    .replace(/\/$/, "");
}

function normalizeLocalPartPreview(value: string) {
  return value.trim().replace(/\s+/g, "").toLowerCase();
}

function formatDateLabel(value: string | null) {
  if (!value) {
    return "아직 검증되지 않았습니다.";
  }

  const date = new Date(value);
  return `${date.getFullYear()}.${String(date.getMonth() + 1).padStart(2, "0")}.${String(
    date.getDate(),
  ).padStart(2, "0")} ${String(date.getHours()).padStart(2, "0")}:${String(
    date.getMinutes(),
  ).padStart(2, "0")}`;
}

function openChannelTalk() {
  const channel = (
    window as Window & {
      ChannelIO?: (command: string) => void;
    }
  ).ChannelIO;

  if (typeof channel === "function") {
    channel("showMessenger");
  }
}

function formatRecordHost(host: string, domain: string) {
  return host === domain ? "@" : host;
}

function inferDkimKeySize(dkimPublicKey: string | undefined) {
  return dkimPublicKey && dkimPublicKey.length < 300 ? 1024 : 2048;
}

function DkimKeySizeSelector({
  value,
  onChange,
  plain = false,
}: {
  value: DkimKeySize;
  onChange: (value: DkimKeySize) => void;
  plain?: boolean;
}) {
  const [isTooltipOpen, setIsTooltipOpen] = useState(false);
  const isRecommended = value === 2048;

  return (
    <StaticUiLocalizer>
      <div className={plain ? "py-3" : "rounded-[14px] border border-[#dbe5f7] bg-[#f8fbff] px-3.5 py-3"}>
      <input name="dkimKeySize" type="hidden" value={value} />
      <div className="flex flex-wrap items-center justify-between gap-2">
        <div className="flex items-center gap-1.5">
          <p className="text-[13px] font-semibold text-[#4f6284]">DKIM 키 길이</p>
          <div className="relative">
            <button
              type="button"
              aria-controls="dkim-key-size-help"
              aria-expanded={isTooltipOpen}
              aria-label="DKIM 키 길이 안내"
              onClick={() => setIsTooltipOpen((current) => !current)}
              className="flex h-5 w-5 items-center justify-center rounded-full border border-[#b9c9e3] bg-white text-[11px] font-bold text-[#607594] transition-colors hover:border-[#8eb2ef] hover:text-[#2f6df6]"
            >
              i
            </button>
            {isTooltipOpen ? (
              <div
                id="dkim-key-size-help"
                role="tooltip"
                className="absolute left-0 top-7 z-20 w-[min(300px,calc(100vw-3rem))] rounded-[12px] border border-[#d5e2f7] bg-white p-3 text-[12px] leading-5 text-[#526782] shadow-[0_12px_30px_rgba(38,73,130,0.16)]"
              >
                2048-bit는 권장되는 기본 설정입니다. 카페24처럼 긴 TXT 값을 등록할 수 없는 DNS를 사용할 때만 1024-bit 호환 모드를 선택하세요. 저장 후 키 길이를 바꾸려면 DKIM 키를 다시 발급해야 합니다.
              </div>
            ) : null}
          </div>
        </div>
        <span className="text-[12px] font-medium text-[#7183a1]">
          {isRecommended ? "권장 설정" : "DNS 호환 모드"}
        </span>
      </div>

      <div className="mt-3 inline-grid grid-cols-[auto_48px_auto] items-center gap-x-3">
        <span
          className={`whitespace-nowrap text-[12px] font-semibold transition-colors ${
            isRecommended ? "text-[#91a0b6]" : "text-[#245ac9]"
          }`}
        >
          1024-bit
        </span>
        <button
          type="button"
          role="switch"
          aria-checked={isRecommended}
          aria-label={`DKIM 키 길이: ${value}-bit`}
          onClick={() => onChange(isRecommended ? 1024 : 2048)}
          className={`relative h-7 min-w-[48px] max-w-[48px] rounded-full border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#8db8ff] focus-visible:ring-offset-2 ${
            isRecommended
              ? "border-[#2f6df6] bg-[#2f6df6]"
              : "border-[#9bb9ec] bg-[#dce9ff]"
          }`}
        >
          <span
            className={`absolute left-0.5 top-0.5 h-[22px] w-[22px] rounded-full bg-white shadow-[0_2px_5px_rgba(23,55,106,0.24)] transition-transform ${
              isRecommended ? "translate-x-[22px]" : "translate-x-0"
            }`}
          />
        </button>
        <span
          className={`whitespace-nowrap text-[12px] font-semibold transition-colors ${
            isRecommended ? "text-[#245ac9]" : "text-[#91a0b6]"
          }`}
        >
          2048-bit
        </span>
      </div>
      <p className="mt-2 text-[12px] leading-5 text-[#7183a1]">
        {isRecommended
          ? "대부분의 DNS 서비스에 권장되는 보안 키 길이입니다."
          : "TXT 값 길이가 255자 안팎으로 제한된 DNS 서비스용 설정입니다."}
      </p>
      </div>
    </StaticUiLocalizer>
  );
}

function createPreviewDnsRows(input: {
  dkimEnabled: boolean;
  domain: string;
  dkimSelector: string;
  dkimPublicKey: string;
  mxHostname: string;
  useSavedDns: boolean;
  savedRows: MailSetupOverview["dnsRecords"];
}) {
  const fallbackRows: DnsRow[] = [
    {
      key: "mx-root",
      type: "MX",
      host: "@",
      value: `${input.mxHostname}.`,
      ttl: "3600",
      priorityValue: "10",
      statusLabel: "저장 전",
      statusTone: "neutral",
      copyValue: `${input.mxHostname}.`,
    },
    {
      key: "spf-root",
      type: "TXT",
      host: "@",
      value: `v=spf1 include:${input.mxHostname} -all`,
      ttl: "3600",
      priorityValue: "-",
      statusLabel: "저장 전",
      statusTone: "neutral",
      copyValue: `v=spf1 include:${input.mxHostname} -all`,
    },
    {
      key: "dkim-root",
      type: "TXT",
      host: `${input.dkimSelector}._domainkey`,
      value: input.dkimPublicKey
        ? `v=DKIM1; k=rsa; p=${input.dkimPublicKey}`
        : `${input.domain} 저장 후 실제 DKIM 공개키가 이 칸에 표시됩니다.`,
      ttl: "3600",
      priorityValue: "-",
      statusLabel: input.dkimPublicKey ? "저장됨" : "저장 후 생성",
      statusTone: input.dkimPublicKey ? "success" : "neutral",
      copyValue: input.dkimPublicKey
        ? `v=DKIM1; k=rsa; p=${input.dkimPublicKey}`
        : "",
    },
    {
      key: "dmarc-root",
      type: "TXT",
      host: "_dmarc",
      value: "v=DMARC1; p=none; rua=mailto:dmarc@officialsite.kr",
      ttl: "3600",
      priorityValue: "-",
      statusLabel: "저장 전",
      statusTone: "neutral",
      copyValue: "v=DMARC1; p=none; rua=mailto:dmarc@officialsite.kr",
    },
  ];
  if (!input.dkimEnabled) {
    const dkimIndex = fallbackRows.findIndex((row) => row.key === "dkim-root");

    if (dkimIndex >= 0) {
      fallbackRows.splice(dkimIndex, 1);
    }
  }

  if (!input.useSavedDns) {
    return fallbackRows;
  }

  const savedRowMap = new Map(
    input.savedRows.map(
      (record) => [`${record.type}-${record.host}`, record] as const,
    ),
  );

  return fallbackRows.map((row) => {
    const hostName = row.host === "@" ? input.domain : row.host;
    const savedRow = savedRowMap.get(`${row.type}-${hostName}`);

    if (!savedRow) {
      return row;
    }

    const isDkimRecord = savedRow.host.endsWith("._domainkey");

    return {
      key: `${savedRow.type}-${savedRow.host}`,
      type: savedRow.type,
      host: formatRecordHost(savedRow.host, input.domain),
      value: savedRow.value,
      ttl: "3600",
      priorityValue: savedRow.priority ? String(savedRow.priority) : "-",
      statusLabel:
        savedRow.status === "verified"
          ? "정상"
          : savedRow.status === "failed"
            ? isDkimRecord
              ? "설정 권장"
              : "불일치"
            : "확인 전",
      statusTone:
        savedRow.status === "verified"
          ? "success"
          : savedRow.status === "failed"
            ? isDkimRecord
              ? "warning"
              : "error"
            : "neutral",
      copyValue: savedRow.value,
    } satisfies DnsRow;
  });
}

function statusTextClass(tone: DnsRow["statusTone"]) {
  if (tone === "success") {
    return "text-[#2d8153]";
  }

  if (tone === "error") {
    return "text-[#b04c63]";
  }

  if (tone === "warning") {
    return "text-[#a36a13]";
  }

  return "text-[#5f7190]";
}

function hasDkimDnsWarning(overview: MailSetupOverview | null) {
  if (!overview?.mailConfigured || !overview.dkimEnabled) {
    return false;
  }

  const dkimRecord = overview.dnsRecords.find((record) =>
    record.host.endsWith("._domainkey"),
  );

  return dkimRecord?.status !== "verified";
}

function hasMailSetupDnsIssue(overview: MailSetupOverview | null) {
  if (!overview) {
    return false;
  }

  return overview.dnsRecords.some((record) => {
    const isDkimRecord = record.host.endsWith("._domainkey");

    if (isDkimRecord && !overview.dkimEnabled) {
      return false;
    }

    return record.status !== "verified";
  });
}

function hasRequiredDnsMismatch(overview: MailSetupOverview | null) {
  if (!overview?.mailConfigured) {
    return false;
  }

  return overview.dnsRecords.some(
    (record) =>
      !record.host.endsWith("._domainkey") && record.status !== "verified",
  );
}

function getDnsRecordFunnelDetail(row: DnsRow, index: number) {
  const host = row.host.toLowerCase();
  const kind = host.includes("_domainkey")
    ? "dkim"
    : host.includes("_dmarc")
      ? "dmarc"
      : row.type === "MX"
        ? "mx"
        : "spf";
  return `record_${kind}_${index + 1}`;
}

function connectionBadge(input: {
  overview: MailSetupOverview | null;
  useSavedDns: boolean;
  hasDraftDomain: boolean;
}) {
  if (!input.overview) {
    return {
      label: input.hasDraftDomain ? "입력 중" : "설정 전",
      className: "om-badge-info",
    };
  }

  if (input.overview.mailConfigured) {
    if (hasRequiredDnsMismatch(input.overview)) {
      return {
        label: "DNS 확인 필요",
        className: "om-badge-danger",
      };
    }

    if (hasDkimDnsWarning(input.overview)) {
      return {
        label: "DKIM 확인 필요",
        className: "om-badge-warning",
      };
    }

    return {
      label: "연결 완료",
      className: "om-badge-success",
    };
  }

  if (input.overview.status === "failed") {
    return {
      label: "검증 실패",
      className: "om-badge-danger",
    };
  }

  if (input.overview.status === "verified" && input.useSavedDns) {
    return {
      label: "메일 연결 대기",
      className: "om-badge-info",
    };
  }

  return {
    label: "DNS 대기",
    className: "om-badge-info",
  };
}

function SettingsNavIcon({ section }: { section: MailSetupSection }) {
  const commonProps = {
    "aria-hidden": true,
    className: "h-[17px] w-[17px]",
    fill: "none",
    stroke: "currentColor",
    strokeLinecap: "round" as const,
    strokeLinejoin: "round" as const,
    strokeWidth: 1.9,
    viewBox: "0 0 24 24",
  };

  if (section === "account") {
    return (
      <svg {...commonProps}>
        <path d="M12 12.4a4.1 4.1 0 1 0 0-8.2 4.1 4.1 0 0 0 0 8.2Z" />
        <path d="M4.8 20.1a7.2 7.2 0 0 1 14.4 0" />
      </svg>
    );
  }

  if (section === "classification") {
    return (
      <svg {...commonProps}>
        <path d="M4 6.5h10" />
        <path d="M4 12h7" />
        <path d="M4 17.5h5" />
        <path d="m14 14 3 3 4-5" />
      </svg>
    );
  }

  if (section === "contacts") {
    return (
      <svg {...commonProps}>
        <circle cx="9" cy="8" r="3" />
        <path d="M3.8 19a5.2 5.2 0 0 1 10.4 0" />
        <path d="M17 8v6M14 11h6" />
      </svg>
    );
  }

  if (section === "spam") {
    return (
      <svg {...commonProps}>
        <path d="M12 3.8 18.5 6v5.8c0 3.8-2.6 6.6-6.5 8.4-3.9-1.8-6.5-4.6-6.5-8.4V6z" />
        <path d="M12 8.5v4M12 16h.01" />
      </svg>
    );
  }

  if (section === "storage") {
    return (
      <svg {...commonProps}>
        <path d="M4.5 7.5A1.5 1.5 0 0 1 6 6h3l1.7 2H18a1.5 1.5 0 0 1 1.5 1.5v6.8A1.7 1.7 0 0 1 17.8 18H6.2a1.7 1.7 0 0 1-1.7-1.7z" />
      </svg>
    );
  }

  if (section === "domain") {
    return (
      <svg {...commonProps}>
        <circle cx="12" cy="12" r="8.3" />
        <path d="M3.9 12h16.2" />
        <path d="M12 3.7c2.1 2.2 3.2 5 3.2 8.3s-1.1 6.1-3.2 8.3" />
        <path d="M12 3.7c-2.1 2.2-3.2 5-3.2 8.3s1.1 6.1 3.2 8.3" />
      </svg>
    );
  }

  if (section === "assistant") {
    return (
      <svg {...commonProps}>
        <path d="m12 3.6 1.8 4.7 4.6 1.7-4.6 1.8-1.8 4.6-1.8-4.6L5.6 10l4.6-1.7Z" />
        <path d="m18.2 15.3.7 1.8 1.8.7-1.8.7-.7 1.8-.7-1.8-1.8-.7 1.8-.7Z" />
      </svg>
    );
  }

  if (section === "integrations") {
    return (
      <svg {...commonProps}>
        <path d="M8.4 8.3 6.7 6.6a2.7 2.7 0 0 0-3.8 3.8l2.5 2.5a2.7 2.7 0 0 0 3.8 0l1.4-1.4" />
        <path d="m15.6 15.7 1.7 1.7a2.7 2.7 0 0 0 3.8-3.8l-2.5-2.5a2.7 2.7 0 0 0-3.8 0l-1.4 1.4" />
        <path d="m8.6 15.4 6.8-6.8" />
      </svg>
    );
  }

  if (section === "members") {
    return (
      <svg {...commonProps}>
        <path d="M9.2 11.2a3.4 3.4 0 1 0 0-6.8 3.4 3.4 0 0 0 0 6.8Z" />
        <path d="M3.8 19.5a5.6 5.6 0 0 1 10.8-2" />
        <path d="M16.6 10.3a2.7 2.7 0 1 0 0-5.4" />
        <path d="M16.5 14.1a5 5 0 0 1 3.7 4.5" />
      </svg>
    );
  }

  if (section === "language") {
    return (
      <svg {...commonProps}>
        <circle cx="12" cy="12" r="8.3" />
        <path d="M3.9 12h16.2" />
        <path d="M12 3.7c2.1 2.2 3.2 5 3.2 8.3s-1.1 6.1-3.2 8.3" />
        <path d="M12 3.7c-2.1 2.2-3.2 5-3.2 8.3s1.1 6.1 3.2 8.3" />
      </svg>
    );
  }

  return (
    <svg {...commonProps}>
      <rect x="4" y="6.2" width="16" height="11.6" rx="2.6" />
      <path d="M4 10h16" />
      <path d="M7.7 14.2h3.3" />
    </svg>
  );
}

function SettingsShell({
  canManageBilling,
  section,
  children,
}: {
  canManageBilling: boolean;
  section: MailSetupSection;
  children: ReactNode;
}) {
  const { t } = useI18n();
  const visibleSettingsSections = canManageBilling
    ? SETTINGS_NAV_SECTIONS
    : SETTINGS_NAV_SECTIONS.filter(
        (item) => item !== "domain" && item !== "members" && item !== "billing",
      );

  return (
    <div className="om-settings-layout om-settings-layout-compact-nav">
      <aside className="om-settings-sidebar hidden xl:block">
        <nav className="om-settings-sidebar-nav">
          {visibleSettingsSections.map((item) => {
            const active = item === section;
            const translatedLabel = t(SECTION_TRANSLATION_KEYS[item].label);

            return (
              <Link
                key={item}
                href={`/mail?panel=setup&section=${item}`}
                prefetch={false}
                aria-label={translatedLabel}
                className={`om-settings-sidebar-link ${
                  active
                    ? "om-settings-sidebar-link-active"
                    : "om-settings-sidebar-link-idle"
                }`}
              >
                <span className="om-settings-sidebar-link-icon">
                  <SettingsNavIcon section={item} />
                </span>
                <span className="om-settings-sidebar-link-label truncate">{translatedLabel}</span>
              </Link>
            );
          })}
        </nav>
      </aside>

      <div className="om-settings-main">
        <div className="om-settings-main-inner om-settings-main-inner-compact">
          <StaticUiLocalizer>{children}</StaticUiLocalizer>
        </div>
      </div>
    </div>
  );
}

function AccountSectionPanel({
  eyebrow,
  title,
  description,
  action,
  children,
}: {
  eyebrow: string;
  title: string;
  description: string;
  action?: ReactNode;
  children?: ReactNode;
}) {
  const { tr } = useI18n();

  return (
    <section className="om-setup-panel bg-white px-3 py-4 sm:px-4 lg:px-5">
      <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
        <div className="min-w-0">
          <p className="text-[12px] font-semibold uppercase tracking-[0.12em] text-[#8aa0c6]">
            {tr(eyebrow)}
          </p>
          <h2 className="mt-1.5 text-[18px] font-semibold tracking-[-0.04em] text-[#16233c] sm:text-[20px]">
            {tr(title)}
          </h2>
          <p className="mt-1.5 max-w-[720px] text-[13px] leading-5 text-[#6f7f99]">
            {tr(description)}
          </p>
        </div>
        {action ? <div className="shrink-0">{action}</div> : null}
      </div>
      {children ? <div className="mt-4">{children}</div> : null}
    </section>
  );
}

function AccountInlineDisplayName({ defaultValue }: { defaultValue: string }) {
  const { tr } = useI18n();
  const router = useRouter();
  const [editing, setEditing] = useState(false);
  const [displayedValue, setDisplayedValue] = useState(defaultValue);
  const [inputValue, setInputValue] = useState(defaultValue);
  const [state, setState] = useState(INITIAL_MAILBOX_DISPLAY_NAME_ACTION_STATE);
  const [pending, setPending] = useState(false);

  const submitDisplayName = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setPending(true);
    const formData = new FormData(event.currentTarget);

    try {
      const result = await updateMailboxDisplayNameAction(state, formData);
      setState(result);

      if (result.status === "success" && result.displayName) {
        setDisplayedValue(result.displayName);
        setInputValue(result.displayName);
        setEditing(false);
        router.refresh();
      }
    } finally {
      setPending(false);
    }
  };

  if (!editing) {
    return (
      <div className="min-w-0">
        <div className="flex min-w-0 items-center gap-1.5">
          <h2 data-i18n-skip className="min-w-0 truncate text-[20px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[22px]">
            <button
              type="button"
              onClick={() => setEditing(true)}
              className="max-w-full cursor-text truncate text-left outline-none"
              aria-label={`${displayedValue} 표시 이름 수정`}
            >
              {displayedValue}
            </button>
          </h2>
          <button
            type="button"
            onClick={() => setEditing(true)}
            aria-label="표시 이름 수정"
            className="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-[8px] text-[#7b8ca8] transition-colors hover:bg-[#f1f5fb] hover:text-[#2f6df6] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#bcd1ff]"
          >
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth="1.8"
              strokeLinecap="round"
              strokeLinejoin="round"
              className="h-[15px] w-[15px]"
              aria-hidden="true"
            >
              <path d="m4.8 15.8-.8 4.2 4.2-.8L18.6 8.8a2.1 2.1 0 0 0-3-3Z" />
              <path d="m13.9 7.5 2.6 2.6" />
            </svg>
          </button>
        </div>
      </div>
    );
  }

  return (
    <div className="min-w-0">
      <form onSubmit={submitDisplayName} className="flex min-w-0 flex-wrap items-center gap-2">
        <input
          autoFocus
          required
          aria-label={tr("표시 이름")}
          name="displayName"
          value={inputValue}
          onChange={(event) => setInputValue(event.target.value)}
          maxLength={191}
          autoComplete="name"
          className="h-10 min-w-[180px] flex-1 rounded-[10px] border border-[#bcd1ff] bg-white px-3 text-[16px] font-semibold tracking-[-0.03em] text-[#16233c] outline-none ring-2 ring-[#edf4ff] sm:text-[18px]"
        />
        <button
          type="submit"
          disabled={pending}
          className="om-btn-primary h-9 shrink-0 rounded-[9px] px-3.5 text-[12px] shadow-none hover:shadow-none disabled:cursor-not-allowed disabled:opacity-60"
        >
          {pending ? tr("저장 중...") : tr("저장")}
        </button>
        <button
          type="button"
          disabled={pending}
          onClick={() => {
            setInputValue(displayedValue);
            setEditing(false);
          }}
          className="h-9 shrink-0 rounded-[9px] border border-[#dbe5f7] bg-white px-3.5 text-[12px] font-semibold text-[#667792] transition-colors hover:bg-[#f7faff] disabled:cursor-not-allowed disabled:opacity-60"
        >
          {tr("취소")}
        </button>
      </form>
      {state.status !== "idle" ? (
        <p
          aria-live="polite"
          className={`mt-2 text-[12px] leading-5 ${
            state.status === "success" ? "text-[#2d8153]" : "text-[#b54a5b]"
          }`}
        >
          {state.message}
        </p>
      ) : null}
    </div>
  );
}

type RecoveryEmailResponse = {
  challengeId?: number;
  error?: string;
  message?: string;
  recoveryEmail?: string;
  verified?: boolean;
};

function RecoveryEmailSettings({
  accountEmail,
  initialEmail,
  initialVerified,
}: {
  accountEmail: string;
  initialEmail: string;
  initialVerified: boolean;
}) {
  const { tr } = useI18n();
  const [savedEmail, setSavedEmail] = useState(initialEmail.trim().toLowerCase());
  const [savedVerified, setSavedVerified] = useState(initialVerified);
  const [email, setEmail] = useState(initialEmail);
  const [challengeId, setChallengeId] = useState<number | null>(null);
  const [code, setCode] = useState("");
  const [sending, setSending] = useState(false);
  const [verifying, setVerifying] = useState(false);
  const [notice, setNotice] = useState<{ tone: "error" | "success"; message: string } | null>(null);
  const normalizedEmail = email.trim().toLowerCase();
  const unchangedVerified =
    savedVerified && Boolean(savedEmail) && normalizedEmail === savedEmail;

  const resetVerification = () => {
    setChallengeId(null);
    setCode("");
    setNotice(null);
  };

  const sendCode = async () => {
    if (!normalizedEmail) {
      setNotice({ tone: "error", message: "보조 이메일을 입력해주세요." });
      return;
    }

    if (normalizedEmail === accountEmail.trim().toLowerCase()) {
      setNotice({
        tone: "error",
        message: "로그인 계정과 다른 이메일 주소를 입력해주세요.",
      });
      return;
    }

    setSending(true);
    setNotice(null);

    try {
      const response = await fetch("/api/account/recovery-email", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ challengeId, recoveryEmail: normalizedEmail }),
      });
      const payload = (await response.json().catch(() => null)) as RecoveryEmailResponse | null;

      if (!response.ok || !payload?.challengeId) {
        throw new Error(payload?.message ?? "인증번호를 보내지 못했습니다.");
      }

      setChallengeId(payload.challengeId);
      setCode("");
      setNotice({
        tone: "success",
        message: "입력한 주소로 인증번호를 보냈습니다.",
      });
    } catch (error) {
      setNotice({
        tone: "error",
        message: error instanceof Error ? error.message : "인증번호를 보내지 못했습니다.",
      });
    } finally {
      setSending(false);
    }
  };

  const verifyAndSave = async () => {
    if (!challengeId || code.length !== 6) {
      setNotice({ tone: "error", message: "6자리 인증번호를 입력해주세요." });
      return;
    }

    setVerifying(true);
    setNotice(null);

    try {
      const response = await fetch("/api/account/recovery-email", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ challengeId, code, recoveryEmail: normalizedEmail }),
      });
      const payload = (await response.json().catch(() => null)) as RecoveryEmailResponse | null;

      if (!response.ok || !payload?.verified || !payload.recoveryEmail) {
        throw new Error(payload?.message ?? "보조 이메일을 저장하지 못했습니다.");
      }

      setSavedEmail(payload.recoveryEmail);
      setSavedVerified(true);
      setEmail(payload.recoveryEmail);
      setChallengeId(null);
      setCode("");
      setNotice({
        tone: "success",
        message: payload.message ?? "보조 이메일을 저장했습니다.",
      });
    } catch (error) {
      setNotice({
        tone: "error",
        message: error instanceof Error ? error.message : "보조 이메일을 저장하지 못했습니다.",
      });
    } finally {
      setVerifying(false);
    }
  };

  return (
    <div className="max-w-[680px]">
      <div className="flex flex-col gap-2 sm:flex-row sm:items-end">
        <label className="block min-w-0 flex-1">
          <span className="mb-2 block text-[13px] font-semibold text-[#4f6284]">
            {tr("보조 이메일")}
          </span>
          <input
            type="email"
            value={email}
            maxLength={320}
            autoComplete="email"
            onChange={(event) => {
              setEmail(event.target.value);
              resetVerification();
            }}
            placeholder={tr("비밀번호 재설정 링크를 받을 이메일")}
            className="h-10 w-full rounded-[10px] border border-[#dbe5f7] bg-white px-3 text-[14px] text-[#1a2943] outline-none transition-colors placeholder:text-[#97a7c2] focus:border-[#bcd1ff]"
          />
        </label>
        <button
          type="button"
          disabled={sending || unchangedVerified}
          onClick={sendCode}
          className={`h-10 shrink-0 rounded-[10px] px-4 text-[13px] font-semibold transition-colors disabled:cursor-default ${
            unchangedVerified
              ? "border border-[#d9eadf] bg-[#f5faf7] text-[#2d8153]"
              : "om-btn-secondary border border-[#dbe5f7] bg-white text-[#2f6df6] hover:bg-[#f7faff] disabled:opacity-60"
          }`}
        >
          {unchangedVerified
            ? tr("인증 완료")
            : sending
              ? tr("전송 중...")
              : challengeId
                ? tr("인증번호 재발송")
                : tr("인증번호 받기")}
        </button>
      </div>

      {challengeId && !unchangedVerified ? (
        <div className="mt-3 flex flex-col gap-2 sm:flex-row sm:items-end">
          <label className="block min-w-0 flex-1">
            <span className="mb-2 block text-[13px] font-semibold text-[#4f6284]">
              {tr("인증번호")}
            </span>
            <input
              inputMode="numeric"
              value={code}
              onChange={(event) => setCode(event.target.value.replace(/\D+/g, "").slice(0, 6))}
              placeholder={tr("6자리 인증번호")}
              className="h-10 w-full rounded-[10px] border border-[#dbe5f7] bg-white px-3 text-[14px] tracking-[0.12em] text-[#1a2943] outline-none transition-colors placeholder:tracking-normal placeholder:text-[#97a7c2] focus:border-[#bcd1ff]"
            />
          </label>
          <button
            type="button"
            disabled={verifying}
            onClick={verifyAndSave}
            className="om-btn-primary h-10 shrink-0 rounded-[10px] px-4 text-[13px] shadow-none hover:shadow-none disabled:cursor-not-allowed disabled:opacity-60"
          >
            {verifying ? tr("저장 중...") : tr("인증 후 저장")}
          </button>
        </div>
      ) : null}

      <p className="mt-2 text-[12px] leading-5 text-[#7b8ca8]">
        {tr("로그인할 수 없을 때 비밀번호 재설정 링크를 받을 외부 이메일을 등록해주세요.")}
      </p>
      {notice ? (
        <p
          aria-live="polite"
          className={`mt-2 text-[12px] leading-5 ${
            notice.tone === "success" ? "text-[#2d8153]" : "text-[#b54a5b]"
          }`}
        >
          {notice.message}
        </p>
      ) : null}
    </div>
  );
}

function AccountPasswordDialogPanel({
  onClose,
  onSuccess,
}: {
  onClose: () => void;
  onSuccess: (message: string) => void;
}) {
  const { tr } = useI18n();
  const [state, formAction, pending] = useActionState(
    updateRepresentativePasswordAction,
    INITIAL_REPRESENTATIVE_PASSWORD_ACTION_STATE,
  );

  useEffect(() => {
    if (state.status === "success") {
      onSuccess(state.message);
    }
  }, [onSuccess, state.message, state.status]);

  return (
    <div
      className="fixed inset-0 z-[170] flex items-center justify-center bg-[rgba(12,18,31,0.42)] px-4 py-8 backdrop-blur-[3px]"
      onClick={() => {
        if (!pending) {
          onClose();
        }
      }}
    >
      <div
        role="dialog"
        aria-modal="true"
        aria-labelledby="account-password-dialog-title"
        className="w-full max-w-[560px] overflow-hidden rounded-[22px] border border-[#e2eaf7] bg-white shadow-[0_28px_70px_rgba(18,32,65,0.18)]"
        onClick={(event) => event.stopPropagation()}
      >
        <div className="border-b border-[#edf2fb] px-6 py-5">
          <div className="flex items-start justify-between gap-4">
            <div className="min-w-0">
              <p
                id="account-password-dialog-title"
                className="text-[20px] font-semibold tracking-[-0.04em] text-[#16233c]"
              >
                {tr("비밀번호 변경")}
              </p>
              <p className="mt-2 text-[14px] leading-6 text-[#6a7b98]">
                {tr("현재 비밀번호를 확인한 뒤 새 비밀번호를 적용합니다.")}
              </p>
            </div>
            <CloseIconButton
              ariaLabel="비밀번호 변경 닫기"
              className={pending ? "pointer-events-none opacity-60" : ""}
              onClick={() => {
                if (!pending) {
                  onClose();
                }
              }}
            />
          </div>
        </div>

        <form action={formAction} className="px-6 py-6">
          <div className="mt-5 space-y-4">
            <label className="block">
              <span className="mb-2 block text-[13px] font-semibold text-[#4f6284]">
                {tr("현재 비밀번호")}
              </span>
              <input
                required
                type="password"
                name="currentPassword"
                autoComplete="current-password"
                placeholder={tr("현재 비밀번호를 입력하세요")}
                className="h-13 w-full rounded-[16px] border border-[#dbe5f7] bg-white px-4 text-[15px] text-[#1a2943] outline-none transition-colors placeholder:text-[#97a7c2] focus:border-[#bcd1ff]"
              />
            </label>

            <div className="grid gap-4 xl:grid-cols-2">
              <label className="block">
                <span className="mb-2 block text-[13px] font-semibold text-[#4f6284]">
                  {tr("새 비밀번호")}
                </span>
                <input
                  required
                  type="password"
                  name="password"
                  autoComplete="new-password"
                  placeholder={tr("새 비밀번호를 입력하세요")}
                  className="h-13 w-full rounded-[16px] border border-[#dbe5f7] bg-white px-4 text-[15px] text-[#1a2943] outline-none transition-colors placeholder:text-[#97a7c2] focus:border-[#bcd1ff]"
                />
              </label>

              <label className="block">
                <span className="mb-2 block text-[13px] font-semibold text-[#4f6284]">
                  {tr("비밀번호 확인")}
                </span>
                <input
                  required
                  type="password"
                  name="passwordConfirm"
                  autoComplete="new-password"
                  placeholder={tr("같은 비밀번호를 다시 입력하세요")}
                  className="h-13 w-full rounded-[16px] border border-[#dbe5f7] bg-white px-4 text-[15px] text-[#1a2943] outline-none transition-colors placeholder:text-[#97a7c2] focus:border-[#bcd1ff]"
                />
              </label>
            </div>
          </div>

          {state.status === "error" ? (
            <div className="mt-4 rounded-[14px] border border-[#f0d8de] bg-[#fff7f9] px-4 py-3 text-[13px] leading-6 text-[#a34861]">
              {state.message}
            </div>
          ) : null}

          <div className="mt-6 flex items-center justify-end gap-2 border-t border-[#edf2fb] pt-5">
            <button
              type="button"
              disabled={pending}
              onClick={onClose}
              className="om-btn-secondary h-11 rounded-[14px] px-4 text-[13px] text-[#344767] disabled:cursor-not-allowed disabled:opacity-60"
            >
              {tr("취소")}
            </button>
            <SubmitButton
              label={tr("비밀번호 변경")}
              pendingLabel={tr("변경 중...")}
              className="om-btn-primary h-11 rounded-[14px] px-4 text-[13px]"
            />
          </div>
        </form>
      </div>
    </div>
  );
}

function AccountPasswordDialog() {
  const { tr } = useI18n();
  const [open, setOpen] = useState(false);
  const [dialogKey, setDialogKey] = useState(0);
  const [successMessage, setSuccessMessage] = useState("");

  useEffect(() => {
    if (!open) {
      return undefined;
    }

    const previousOverflow = document.body.style.overflow;

    function handleKeyDown(event: KeyboardEvent) {
      if (event.key === "Escape") {
        setOpen(false);
      }
    }

    document.body.style.overflow = "hidden";
    window.addEventListener("keydown", handleKeyDown);

    return () => {
      document.body.style.overflow = previousOverflow;
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [open]);

  useEffect(() => {
    if (!successMessage) {
      return undefined;
    }

    const timer = window.setTimeout(() => {
      setSuccessMessage("");
    }, 3200);

    return () => window.clearTimeout(timer);
  }, [successMessage]);

  return (
    <>
      <div className="flex flex-col items-start gap-3 lg:items-end lg:text-right">
        <button
          type="button"
          onClick={() => {
            setDialogKey((value) => value + 1);
            setOpen(true);
          }}
          className="om-btn-primary h-10 rounded-[10px] px-4 text-[13px] shadow-none hover:shadow-none"
        >
          {tr("비밀번호 변경")}
        </button>
        <p
          className={`text-[12px] leading-5 ${
            successMessage ? "text-[#2d8153]" : "text-[#7b8ca8]"
          }`}
        >
          {successMessage || tr("계정 로그인 비밀번호만 변경됩니다. 외부 연결 전용 비밀번호는 별도로 유지됩니다.")}
        </p>
      </div>

      {open ? (
        <AccountPasswordDialogPanel
          key={dialogKey}
          onClose={() => setOpen(false)}
          onSuccess={(message) => {
            setSuccessMessage(message);
            setOpen(false);
          }}
        />
      ) : null}
    </>
  );
}

export function MailSetupWorkspace({
  section,
  dkimRegenerated,
  overview,
  aiAssistOverview,
  billingOverview,
  billingProvider,
  usesTossPayments,
  polarBillingOverview,
  billingCancellationOverview,
  billingHistoryPage,
  billingHistoryState,
  billingTab,
  managedMembers,
  memberMailboxView,
  planSummary,
  canManageBilling,
  domainSetupAssistanceAvailable,
  sessionCompanyName,
  sessionDisplayName,
  sessionDomain,
  sessionEmail,
  sessionNotificationEmail,
  sessionRecoveryEmail,
  sessionRecoveryEmailVerified,
  sessionMailbox,
  signatureSettings,
}: MailSetupWorkspaceProps) {
  const { t } = useI18n();
  const [copiedRowKey, setCopiedRowKey] = useState("");
  const [verificationHelpOpen, setVerificationHelpOpen] = useState(false);
  const [domainWizardStep, setDomainWizardStep] = useState(0);
  const [domainProvider, setDomainProvider] = useState<DomainProviderId | "">("");
  const [websiteConnection, setWebsiteConnection] =
    useState<WebsiteConnectionState>("");
  const [websiteHostingProvider, setWebsiteHostingProvider] =
    useState<WebsiteHostingProviderId | "">("");
  const [confirmedDnsRows, setConfirmedDnsRows] = useState<string[]>([]);
  const [showConnectedDnsDetails, setShowConnectedDnsDetails] =
    useState(dkimRegenerated || hasMailSetupDnsIssue(overview));
  const [dkimKeySize, setDkimKeySize] = useState<DkimKeySize>(() =>
    inferDkimKeySize(overview?.dkimPublicKey),
  );
  const [domain, setDomain] = useState(overview?.domain || sessionDomain || "");
  const [localPart, setLocalPart] = useState(
    overview?.localPart || sessionMailbox.split("@")[0] || "owner",
  );

  useEffect(() => {
    if (!copiedRowKey) {
      return undefined;
    }

    const timer = window.setTimeout(() => {
      setCopiedRowKey("");
    }, 1800);

    return () => window.clearTimeout(timer);
  }, [copiedRowKey]);

  const sectionTranslationKeys = SECTION_TRANSLATION_KEYS[section];
  const sectionMeta = {
    description: t(sectionTranslationKeys.description),
    label: t(sectionTranslationKeys.label),
    title: t(sectionTranslationKeys.title),
  };
  const normalizedDomain =
    normalizeDomainPreview(domain) ||
    overview?.domain ||
    sessionDomain ||
    "company.co.kr";
  const normalizedLocalPart =
    normalizeLocalPartPreview(localPart) ||
    overview?.localPart ||
    sessionMailbox.split("@")[0] ||
    "owner";
  const previewMailbox = `${normalizedLocalPart}@${normalizedDomain}`;
  const representativeMailbox =
    overview?.mailbox || sessionMailbox || previewMailbox;
  const useSavedDns = Boolean(overview && overview.domain === normalizedDomain);
  const hasDraftDomain = Boolean(normalizeDomainPreview(domain));
  const dkimDnsWarning = hasDkimDnsWarning(overview);
  const requiredDnsMismatch = hasRequiredDnsMismatch(overview);
  const dnsDetailsForcedOpen = hasMailSetupDnsIssue(overview);
  const showDomainForm = !overview;
  const domainWizardStorageKey = `officialmail:domain-wizard:v2:${sessionEmail.toLowerCase()}`;
  const verificationAttemptKey = `officialmail:domain-verify-attempt:${sessionEmail.toLowerCase()}`;
  const verificationFailureEventKey = `${verificationAttemptKey}:failure-recorded`;
  const badge = connectionBadge({ overview, useSavedDns, hasDraftDomain });
  const billingSeatCount = countMailBillingSeatsFromManagedMembers(
    managedMembers.length,
  );
  const estimatedMonthlyCost = planSummary.estimatedMonthlyCost;
  const dnsRows = createPreviewDnsRows({
    dkimEnabled: overview?.dkimEnabled ?? true,
    domain: normalizedDomain,
    dkimSelector: overview?.dkimSelector || "dkim",
    dkimPublicKey: useSavedDns ? overview?.dkimPublicKey || "" : "",
    mxHostname: overview?.mxHostname || "mx1.officialsite.kr",
    useSavedDns,
    savedRows: overview?.dnsRecords ?? [],
  });
  const failedDnsRows = dnsRows.filter((row) => row.statusTone === "error");
  const failedDnsFunnelDetail = failedDnsRows[0]
    ? getDnsRecordFunnelDetail(failedDnsRows[0], 0)
    : "dns_pending";
  const websiteConnectionStep = 1;
  const websiteHostingProviderStep = 2;
  const domainLocationStep = websiteConnection === "yes" ? 3 : 2;
  const domainRegistrationStep = showDomainForm ? domainLocationStep + 1 : null;
  const domainRecordStartStep =
    domainLocationStep + 1 + (domainRegistrationStep === null ? 0 : 1);
  const domainVerifyStep = domainRecordStartStep + dnsRows.length;
  const selectedDomainProvider = DOMAIN_PROVIDERS.find(
    (provider) => provider.id === domainProvider,
  );
  const selectedWebsiteHostingProvider = WEBSITE_HOSTING_PROVIDERS.find(
    (provider) => provider.id === websiteHostingProvider,
  );
  let domainWizardFunnelDetail = "provider";
  if (domainWizardStep === websiteConnectionStep) {
    domainWizardFunnelDetail = "website_connection";
  } else if (
    websiteConnection === "yes" &&
    domainWizardStep === websiteHostingProviderStep
  ) {
    domainWizardFunnelDetail = "website_hosting";
  } else if (domainWizardStep === domainLocationStep) {
    domainWizardFunnelDetail = "dns_location";
  } else if (
    domainRegistrationStep !== null &&
    domainWizardStep === domainRegistrationStep
  ) {
    domainWizardFunnelDetail = "domain_registration";
  } else if (
    domainWizardStep >= domainRecordStartStep &&
    domainWizardStep < domainVerifyStep
  ) {
    const index = domainWizardStep - domainRecordStartStep;
    const row = dnsRows[index];
    domainWizardFunnelDetail = row
      ? getDnsRecordFunnelDetail(row, index)
      : "dns_record";
  } else if (domainWizardStep === domainVerifyStep) {
    domainWizardFunnelDetail = "verification";
  }

  useEffect(() => {
    if (section !== "domain") {
      return;
    }

    try {
      const saved = JSON.parse(
        window.localStorage.getItem(domainWizardStorageKey) ?? "{}",
      ) as {
        confirmedDnsRows?: string[];
        hostingProvider?: WebsiteHostingProviderId;
        provider?: DomainProviderId;
        step?: number;
        websiteConnection?: Exclude<WebsiteConnectionState, "">;
      };

      const timer = window.setTimeout(() => {
        const savedWebsiteConnection =
          saved.websiteConnection === "yes" || saved.websiteConnection === "no"
            ? saved.websiteConnection
            : "";
        const savedHostingProvider = WEBSITE_HOSTING_PROVIDERS.some(
          (provider) => provider.id === saved.hostingProvider,
        )
          ? saved.hostingProvider ?? ""
          : "";

        if (DOMAIN_PROVIDERS.some((provider) => provider.id === saved.provider)) {
          setDomainProvider(saved.provider ?? "");
        }

        setWebsiteConnection(savedWebsiteConnection);
        setWebsiteHostingProvider(savedHostingProvider);

        if (Array.isArray(saved.confirmedDnsRows)) {
          setConfirmedDnsRows(saved.confirmedDnsRows.filter((key) => typeof key === "string"));
        }

        if (Number.isInteger(saved.step)) {
          const savedLocationStep = savedWebsiteConnection === "yes" ? 3 : 2;
          const savedRecordStartStep =
            savedLocationStep + 1 + (showDomainForm ? 1 : 0);
          const savedVerifyStep = savedRecordStartStep + dnsRows.length;
          setDomainWizardStep(Math.max(0, Math.min(savedVerifyStep, saved.step ?? 0)));
        }
      }, 0);

      return () => window.clearTimeout(timer);
    } catch {
      window.localStorage.removeItem(domainWizardStorageKey);
    }
  }, [dnsRows.length, domainWizardStorageKey, section, showDomainForm]);

  useEffect(() => {
    if (section !== "domain") {
      return;
    }

    const searchParams = new URLSearchParams(window.location.search);
    const wasSubmitted = window.sessionStorage.getItem(verificationAttemptKey) === "1";
    const verificationFailed = searchParams.get("error") === "verify-pending";

    if (!overview?.mailConfigured) {
      if (!wasSubmitted && !verificationFailed) {
        return;
      }

      if (window.sessionStorage.getItem(verificationFailureEventKey) !== "1") {
        window.sessionStorage.setItem(verificationFailureEventKey, "1");
        void trackMarketingFunnelEvent(
          "dns_verification_failed",
          failedDnsFunnelDetail,
        );
      }
      window.sessionStorage.removeItem(verificationAttemptKey);
      const timer = window.setTimeout(() => {
        setVerificationHelpOpen(true);
        setDomainWizardStep(domainVerifyStep);
      }, 180);

      return () => window.clearTimeout(timer);
    }

    const shouldUpdateDnsDetails = hasMailSetupDnsIssue(overview) || wasSubmitted;
    const timer = shouldUpdateDnsDetails
      ? window.setTimeout(() => {
          setShowConnectedDnsDetails(hasMailSetupDnsIssue(overview));
        }, 0)
      : undefined;
    window.sessionStorage.removeItem(verificationAttemptKey);
    window.sessionStorage.removeItem(verificationFailureEventKey);

    return () => {
      if (timer !== undefined) {
        window.clearTimeout(timer);
      }
    };
  }, [
    domainVerifyStep,
    failedDnsFunnelDetail,
    overview,
    section,
    verificationAttemptKey,
    verificationFailureEventKey,
  ]);

  useEffect(() => {
    if (section !== "domain") return;
    void trackMarketingFunnelEvent("dns_setup_viewed");
    void trackMarketingFunnelEvent(
      "dns_wizard_step_viewed",
      domainWizardFunnelDetail,
    );
  }, [domainWizardFunnelDetail, section]);

  const persistDomainWizard = (
    nextStep: number,
    nextProvider = domainProvider,
    nextConfirmedRows = confirmedDnsRows,
    nextWebsiteConnection = websiteConnection,
    nextHostingProvider = websiteHostingProvider,
  ) => {
    const clampedStep = Math.max(0, Math.min(domainVerifyStep, nextStep));
    setDomainWizardStep(clampedStep);
    setDomainProvider(nextProvider);
    setConfirmedDnsRows(nextConfirmedRows);
    setWebsiteConnection(nextWebsiteConnection);
    setWebsiteHostingProvider(nextHostingProvider);
    window.localStorage.setItem(
      domainWizardStorageKey,
      JSON.stringify({
        confirmedDnsRows: nextConfirmedRows,
        hostingProvider: nextHostingProvider,
        provider: nextProvider,
        step: clampedStep,
        websiteConnection: nextWebsiteConnection,
      }),
    );
  };

  const copyDnsText = async (key: string, value: string) => {
    if (!value || value === "-") {
      return;
    }

    try {
      await navigator.clipboard.writeText(value);
      setCopiedRowKey(key);
    } catch {
      setCopiedRowKey("");
    }
  };

  const copyRowValue = async (row: DnsRow) => {
    await copyDnsText(row.key, row.copyValue);
  };

  if (section === "account") {
    const accountTitle = sessionDisplayName || sessionCompanyName || "오피셜메일";
    const accountInitials = buildSettingsProfileInitials(
      sessionDisplayName,
      sessionCompanyName,
      sessionEmail,
    );

    return (
      <SettingsShell
        canManageBilling={canManageBilling}
        section={section}
      >
        <div className="om-setup-header">
          <div className="om-setup-header-copy">
            <h1 className="om-page-title text-[#16233c]">
              {sectionMeta.title}
            </h1>
            <p className="om-setup-header-description">
              {sectionMeta.description}
            </p>
          </div>
        </div>

        <div className="om-setup-content">
          <section className="om-setup-panel bg-white px-3 py-4 sm:px-4 lg:px-5">
            <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
              <div className="flex min-w-0 items-center gap-3">
                <div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-[15px] bg-[#edf4ff] text-[15px] font-semibold text-[#2f6df6]">
                  {accountInitials}
                </div>
                <div className="min-w-0">
                  <p className="text-[12px] font-semibold uppercase tracking-[0.12em] text-[#8aa0c6]">
                    대표 계정
                  </p>
                  <div className="mt-1">
                    <AccountInlineDisplayName defaultValue={accountTitle} />
                  </div>
                  <p data-i18n-skip className="mt-1 break-all text-[13px] text-[#6f7f99]">
                    {sessionEmail}
                  </p>
                </div>
              </div>

              <div className="flex flex-wrap gap-2">
                <span className="om-badge om-badge-lg om-badge-info">
                  {planSummary.label}
                </span>
                <span className={`om-badge om-badge-lg ${badge.className}`}>
                  {badge.label}
                </span>
              </div>
            </div>
          </section>

          <AccountSectionPanel
            eyebrow="계정 복구"
            title="보조 이메일"
            description="비밀번호를 잊었을 때 재설정 링크와 중요한 계정 알림을 받을 주소입니다. 변경할 주소의 인증을 완료해야 저장됩니다."
          >
            <RecoveryEmailSettings
              accountEmail={sessionEmail}
              initialEmail={sessionRecoveryEmail}
              initialVerified={sessionRecoveryEmailVerified}
            />
          </AccountSectionPanel>

          <AccountSectionPanel
            eyebrow="보안"
            title="비밀번호 변경"
            description="현재 비밀번호를 확인한 뒤 로그인 비밀번호를 변경합니다. 외부 연결 전용 비밀번호는 별도로 유지됩니다."
            action={<AccountPasswordDialog />}
          />

          <AccountSectionPanel
            eyebrow="발신 정보"
            title="메일 서명"
            description="이름과 연락처 같은 고정 문구 또는 명함 이미지를 저장하면 새 메일, 답장, 전달 작성 시 자동으로 삽입됩니다."
          >
            <MailSignatureSettingsPanel initialSettings={signatureSettings} />
          </AccountSectionPanel>
        </div>
      </SettingsShell>
    );
  }

  if (section === "assistant") {
    return (
      <SettingsShell
        canManageBilling={canManageBilling}
        section={section}
      >
        <MailAiAssistPanel
          embedded
          overview={aiAssistOverview}
          planSummary={planSummary}
          canManageBilling={canManageBilling}
        />
      </SettingsShell>
    );
  }

  if (section === "classification") {
    return (
      <SettingsShell canManageBilling={canManageBilling} section={section}>
        <MailAutoClassificationPanel />
      </SettingsShell>
    );
  }

  if (section === "contacts") {
    return (
      <SettingsShell canManageBilling={canManageBilling} section={section}>
        <MailAddressBookPanel />
      </SettingsShell>
    );
  }

  if (section === "spam") {
    return (
      <SettingsShell canManageBilling={canManageBilling} section={section}>
        <MailSpamSettingsPanel />
      </SettingsShell>
    );
  }

  if (section === "storage") {
    return (
      <SettingsShell canManageBilling={canManageBilling} section={section}>
        <MailStorageSettingsPanel />
      </SettingsShell>
    );
  }

  if (section === "integrations") {
    return (
      <SettingsShell
        canManageBilling={canManageBilling}
        section={section}
      >
        <MailIntegrationsPanel
          mailbox={representativeMailbox}
          planAvailable={planSummary.tier === "growth"}
        />
      </SettingsShell>
    );
  }

  if (section === "members") {
    return (
      <SettingsShell
        canManageBilling={canManageBilling}
        section={section}
      >
        <MailMembersPanel
          embedded
          canManageBilling={canManageBilling}
          domain={normalizedDomain}
          memberMailboxView={memberMailboxView}
          members={managedMembers}
          planSummary={planSummary}
          representativeDisplayName={sessionDisplayName}
          representativeMailbox={representativeMailbox}
        />
      </SettingsShell>
    );
  }

  if (section === "billing") {
    return (
      <SettingsShell
        canManageBilling={canManageBilling}
        section={section}
      >
        <div className="om-setup-header lg:flex-row lg:items-start lg:gap-5">
          <div className="om-setup-header-copy">
            <h1 className="om-page-title text-[#16233c]">
              {sectionMeta.title}
            </h1>
            <p className="om-setup-header-description">
              {sectionMeta.description}
            </p>
          </div>
        </div>

        <div className="om-setup-content">
          {billingProvider === "polar" ? (
            <PolarBillingModule
              billingOverview={polarBillingOverview}
              canManageBilling={canManageBilling}
              isComplimentaryGrowthPlan={planSummary.isComplimentary}
              managedMembers={managedMembers}
              planSummary={planSummary}
              representativeMailbox={representativeMailbox}
            />
          ) : (
            <TossBillingModule
              billingOverview={billingOverview}
              usesTossPayments={usesTossPayments}
              cancellationOverview={billingCancellationOverview}
              currentTab={billingTab}
              billingSeatCount={billingSeatCount}
              canManageBilling={canManageBilling}
              growthPlanEstimatedMonthlyCost={estimatedMonthlyCost}
              historyPage={billingHistoryPage}
              historyState={billingHistoryState}
              isComplimentaryGrowthPlan={planSummary.isComplimentary}
              managedMembers={managedMembers}
              representativeMailbox={representativeMailbox}
            />
          )}
        </div>
      </SettingsShell>
    );
  }

  if (section === "language") {
    return (
      <SettingsShell canManageBilling={canManageBilling} section={section}>
        <div className="om-setup-header">
          <div className="om-setup-header-copy">
            <h1 className="om-page-title text-[#16233c]">{sectionMeta.title}</h1>
            <p className="om-setup-header-description">{sectionMeta.description}</p>
          </div>
        </div>
        <MailLanguageSettingsPanel />
      </SettingsShell>
    );
  }

  const activeDnsRowIndex = domainWizardStep - domainRecordStartStep;
  const activeDnsRow =
    activeDnsRowIndex >= 0 && activeDnsRowIndex < dnsRows.length
      ? dnsRows[activeDnsRowIndex]
      : null;
  const wizardProgress = Math.round(
    ((Math.min(domainWizardStep, domainVerifyStep) + 1) / (domainVerifyStep + 1)) * 100,
  );

  return (
    <SettingsShell canManageBilling={canManageBilling} section="domain">
      <div className="om-setup-header lg:flex-row lg:items-start lg:justify-between lg:gap-5">
        <div className="om-setup-header-copy">
          <h1 className="om-page-title text-[#16233c]">도메인 연결</h1>
          <p className="om-setup-header-description">
            안내에 따라 한 단계씩 완료하면 대표 메일을 사용할 수 있습니다.
          </p>
        </div>
        <Link
          href={`${OFFICIAL_MAIL_GUIDE_URL}#domain`}
          target="_blank"
          rel="noopener noreferrer"
          className="om-btn-secondary h-10 rounded-[10px] px-4 text-[13px] shadow-none hover:shadow-none"
        >
          전체 가이드 보기
        </Link>
      </div>

      <div className="om-setup-content">
        {overview?.mailConfigured ? (
          <>
            <section
              className={`relative isolate overflow-hidden border-b px-3 py-7 sm:px-4 lg:px-5 lg:py-9 ${
                requiredDnsMismatch
                  ? "border-[#efd0d8] bg-[radial-gradient(circle_at_88%_10%,rgba(225,76,112,0.14),transparent_34%),linear-gradient(120deg,#fffafb_0%,#fff3f6_55%,#fffbfc_100%)]"
                  : dkimDnsWarning
                    ? "border-[#f0d79a] bg-[radial-gradient(circle_at_88%_10%,rgba(245,158,11,0.17),transparent_34%),linear-gradient(120deg,#fffdf7_0%,#fff8e8_55%,#fffdf8_100%)]"
                    : "border-[#dbe7f8] bg-[radial-gradient(circle_at_88%_10%,rgba(47,109,246,0.16),transparent_34%),linear-gradient(120deg,#f8fbff_0%,#eef4ff_55%,#f7faff_100%)]"
              }`}
            >
              <div className="relative flex flex-col gap-5 lg:flex-row lg:items-center lg:justify-between">
                <div className="flex min-w-0 items-start gap-4">
                  <span
                    className={`inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-full text-white ${
                      requiredDnsMismatch
                        ? "bg-[#d95572] shadow-[0_12px_28px_rgba(217,85,114,0.24)]"
                        : dkimDnsWarning
                          ? "bg-[#e6a11b] shadow-[0_12px_28px_rgba(230,161,27,0.24)]"
                          : "bg-[#2f6df6] shadow-[0_12px_28px_rgba(47,109,246,0.24)]"
                    }`}
                  >
                    {requiredDnsMismatch || dkimDnsWarning ? (
                      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-5 w-5" aria-hidden="true">
                        <path d="M12 4 21 20H3Z" />
                        <path d="M12 9v5" />
                        <path d="M12 17.2h.01" />
                      </svg>
                    ) : (
                      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-5 w-5" aria-hidden="true">
                        <path d="m5 12 4.2 4.2L19 6.8" />
                      </svg>
                    )}
                  </span>
                  <div className="min-w-0">
                    <p className={`text-[12px] font-semibold ${requiredDnsMismatch ? "text-[#aa4058]" : dkimDnsWarning ? "text-[#a36a13]" : "text-[#2f6df6]"}`}>
                      {requiredDnsMismatch ? "DNS 연결 경고" : dkimDnsWarning ? "연결됨 · DKIM 경고" : "연결 완료"}
                    </p>
                    <h2 className="mt-1 text-[22px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[26px]">
                      <span data-i18n-skip>{normalizedDomain}</span>{" "}
                      <span>
                        {requiredDnsMismatch
                          ? "DNS 연결 상태를 다시 확인해야 합니다"
                          : dkimDnsWarning
                            ? "연결은 완료됐지만 DKIM 확인이 필요합니다"
                            : "연결이 완료되었습니다"}
                      </span>
                    </h2>
                    <p className="mt-2 text-[13px] leading-6 text-[#667b9d]">
                      {requiredDnsMismatch ? (
                        <>
                          <span>필수 DNS 항목이 현재 값과 일치하지 않습니다. 아래 불일치 항목을 수정한 뒤 다시 확인해주세요.</span>{" "}
                        </>
                      ) : dkimDnsWarning ? (
                        <>
                          <span>메일 송수신은 가능하지만 발신 메일이 스팸으로 분류될 수 있습니다. 아래 DKIM 값을 확인해주세요.</span>{" "}
                        </>
                      ) : (
                        <>
                          <span data-i18n-skip>{previewMailbox}</span>{" "}
                          <span>주소로 메일을 주고받을 수 있습니다.</span>{" "}
                        </>
                      )}
                      <span data-i18n-skip={Boolean(overview.verifiedAt)}>
                        {formatDateLabel(overview.verifiedAt)}
                      </span>
                      {overview.verifiedAt ? <> <span>검증</span></> : null}
                    </p>
                  </div>
                </div>
                <div className="flex shrink-0 flex-wrap gap-2 pl-[60px] lg:pl-0">
                  <form action={verifyMailSetupAction}>
                    <SubmitButton
                      label="연결 다시 확인"
                      pendingLabel="확인 중..."
                      className="om-btn-primary h-10 rounded-[10px] px-4 text-[13px] shadow-none hover:shadow-none"
                    />
                  </form>
                  <button
                    type="button"
                    onClick={() => {
                      if (!dnsDetailsForcedOpen) {
                        setShowConnectedDnsDetails((current) => !current);
                      }
                    }}
                    disabled={dnsDetailsForcedOpen}
                    className="om-btn-secondary h-10 cursor-pointer rounded-[10px] px-4 text-[13px] shadow-none hover:shadow-none disabled:cursor-default disabled:opacity-75"
                  >
                    {dnsDetailsForcedOpen
                      ? "DNS 상세 확인 필요"
                      : showConnectedDnsDetails
                        ? "DNS 상세 닫기"
                        : "DNS 상세 보기"}
                  </button>
                </div>
              </div>
            </section>

            {showConnectedDnsDetails || dnsDetailsForcedOpen ? (
              <section className="om-setup-panel px-3 py-5 sm:px-4 lg:px-5">
                <div className="flex flex-col gap-1.5 border-b border-[#edf1f6] pb-4 sm:flex-row sm:items-end sm:justify-between">
                  <div>
                    <h3 className="text-[16px] font-semibold tracking-[-0.03em] text-[#16233c]">현재 DNS 설정</h3>
                    <p className="mt-1 text-[12px] leading-5 text-[#7183a1]">정상 연결 후에는 값을 임의로 변경하지 마세요.</p>
                  </div>
                  <span className={`om-badge om-badge-lg ${badge.className}`}>{badge.label}</span>
                </div>

                {dkimRegenerated ? (
                  <div
                    role="status"
                    className="mt-4 rounded-[16px] border border-[#cfe0ff] bg-[#f2f7ff] px-4 py-3 text-[13px] leading-6 text-[#31527f]"
                  >
                    <strong className="font-semibold text-[#245dcc]">새 DKIM 키 발급 완료</strong>
                    <span className="ml-2">아래 DKIM TXT 값을 DNS에 반영한 뒤 연결 상태를 다시 확인해주세요.</span>
                  </div>
                ) : null}

                {dkimDnsWarning ? (
                  <div
                    role="status"
                    className="mt-4 rounded-[16px] border border-[#f0d79a] bg-[#fff9ea] px-4 py-3 text-[13px] leading-6 text-[#7c5a18]"
                  >
                    <strong className="font-semibold text-[#9a651b]">DKIM 설정 경고</strong>
                    <span className="ml-2">
                      현재 DKIM 공개키가 DNS와 일치하지 않습니다. 연결과 수신은 유지되지만 외부 수신처에서 발신 메일을 스팸으로 분류하거나 거부할 수 있습니다.
                    </span>
                  </div>
                ) : null}

                <form action={updateMailSetupDkimUsageAction} className="flex flex-col gap-3 border-b border-[#edf1f6] py-4 sm:flex-row sm:items-center sm:justify-between">
                  <input type="hidden" name="dkimEnabled" value={overview.dkimEnabled ? "0" : "1"} />
                  <div>
                    <p className="text-[13px] font-semibold text-[#30425f]">DKIM 사용</p>
                    <p className="mt-1 text-[12px] leading-5 text-[#7183a1]">발신 신뢰도를 위해 사용을 권장합니다.</p>
                  </div>
                  <button type="submit" role="switch" aria-checked={overview.dkimEnabled} className={`relative h-6 w-11 shrink-0 rounded-full ${overview.dkimEnabled ? "bg-[#2f6df6]" : "bg-[#c8d4e8]"}`}>
                    <span className={`absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white shadow-sm transition-transform ${overview.dkimEnabled ? "translate-x-[20px]" : "translate-x-0"}`} />
                  </button>
                </form>

                {overview.dkimEnabled ? (
                  <form action={regenerateMailSetupDkimAction} className="flex flex-col gap-3 border-b border-[#edf1f6] py-4 lg:flex-row lg:items-end lg:justify-between">
                    <div className="min-w-0 flex-1"><DkimKeySizeSelector value={dkimKeySize} onChange={setDkimKeySize} plain /></div>
                    <SubmitButton label="DKIM 키 다시 발급" pendingLabel="새 키 발급 중..." className="om-btn-secondary h-10 rounded-[10px] px-4 text-[13px]" />
                  </form>
                ) : null}

                <div className="overflow-x-auto">
                  <table className="min-w-[820px] w-full border-collapse">
                    <thead><tr className="border-b border-[#edf1f6] text-left text-[12px] font-semibold text-[#7a8ba8]"><th className="px-3 py-3">유형</th><th className="px-3 py-3">호스트</th><th className="px-3 py-3">값</th><th className="px-3 py-3">우선순위</th><th className="px-3 py-3">상태</th><th className="px-3 py-3 text-right">복사</th></tr></thead>
                    <tbody>{dnsRows.map((row) => (
                      <tr
                        key={row.key}
                        className={`border-b border-[#edf1f6] align-top last:border-0 ${
                          dkimRegenerated && row.key === "dkim-root" ? "bg-[#f6f9ff]" : ""
                        }`}
                      >
                        <td className="px-3 py-3 text-[13px] font-semibold text-[#16233c]">{row.type}</td>
                        <td className="px-3 py-3 text-[13px] text-[#30425f]">{row.host}</td>
                        <td className="px-3 py-3"><p className="max-w-[560px] break-all text-[12px] leading-5 text-[#30425f]">{row.value}</p></td>
                        <td className="px-3 py-3 text-[13px] text-[#5f7190]">{row.priorityValue}</td>
                        <td className={`px-3 py-3 text-[13px] font-medium ${statusTextClass(row.statusTone)}`}>{row.statusLabel}</td>
                        <td className="px-3 py-3 text-right"><button type="button" onClick={() => copyRowValue(row)} className="om-btn-secondary h-9 min-w-[82px] rounded-[10px] px-3 text-[12px]">{copiedRowKey === row.key ? "복사됨" : "값 복사"}</button></td>
                      </tr>
                    ))}</tbody>
                  </table>
                </div>
              </section>
            ) : null}
          </>
        ) : (
          <section className="om-setup-panel overflow-hidden bg-white">
            <div className="border-b border-[#e7edf7] bg-[#fbfcff] px-3 py-4 sm:px-4 lg:px-5">
              <div className="flex items-center justify-between gap-4">
                <div>
                  <p className="text-[12px] font-semibold text-[#2f6df6]">도메인 연결 안내</p>
                  <p className="mt-1 text-[13px] font-semibold text-[#30425f]">{domainWizardStep + 1} / {domainVerifyStep + 1} 단계</p>
                </div>
                <p className="text-[12px] text-[#7b8ca8]">약 5분</p>
              </div>
              <div className="mt-3 h-1.5 overflow-hidden rounded-full bg-[#e8eef8]">
                <div className="h-full rounded-full bg-[#2f6df6] transition-[width] duration-500 ease-out" style={{ width: `${wizardProgress}%` }} />
              </div>
            </div>

            <div className="mx-auto w-full max-w-[880px] px-3 py-7 sm:px-6 sm:py-9 lg:px-8 lg:py-11">
              {domainWizardStep === 0 ? (
                <div>
                  <p className="text-[12px] font-semibold text-[#2f6df6]">첫 번째 질문</p>
                  <h2 className="mt-2 text-[24px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[30px]">도메인을 어디에서 구매하셨나요?</h2>
                  <p className="mt-3 text-[13px] leading-6 text-[#6d7f9d]">홈페이지를 만든 곳이 아니라 도메인 결제 내역이 있는 업체를 선택해주세요. 정확하지 않아도 다음 단계에서 다시 확인할 수 있습니다.</p>
                  <div className="mt-6 grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
                    {DOMAIN_PROVIDERS.map((provider) => {
                      const selected = domainProvider === provider.id;
                      return (
                        <button key={provider.id} type="button" aria-pressed={selected} onClick={() => persistDomainWizard(0, provider.id)} className={`min-h-[82px] cursor-pointer rounded-[14px] border px-4 py-3 text-left transition-all ${selected ? "border-[#2f6df6] bg-[#f2f6ff] shadow-[0_8px_22px_rgba(47,109,246,0.1)]" : "border-[#e1e8f3] bg-white hover:border-[#bfd1f5] hover:bg-[#fafcff]"}`}>
                          <span className={`block text-[14px] font-semibold ${selected ? "text-[#2f6df6]" : "text-[#263957]"}`}>{provider.label}</span>
                          <span className="mt-1.5 block text-[11px] leading-4 text-[#7b8ca8]">{provider.hint}</span>
                        </button>
                      );
                    })}
                  </div>
                  <div className="mt-7 flex justify-end">
                    <button type="button" disabled={!domainProvider} onClick={() => persistDomainWizard(websiteConnectionStep)} className="om-btn-primary h-11 min-w-[112px] rounded-[10px] px-5 text-[13px] disabled:cursor-not-allowed disabled:opacity-45">다음</button>
                  </div>
                </div>
              ) : null}

              {domainWizardStep === websiteConnectionStep ? (
                <div>
                  <p className="text-[12px] font-semibold text-[#2f6df6]">잠시만요!</p>
                  <h2 className="mt-2 text-[24px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[30px]">홈페이지가 이 도메인에 연결되어 있나요?</h2>
                  <p className="mt-3 text-[13px] leading-6 text-[#6d7f9d]">브라우저 주소창에 {normalizedDomain}을 입력했을 때 현재 운영 중인 홈페이지나 쇼핑몰이 열리는지 알려주세요.</p>
                  <div className="mt-6 grid gap-3 sm:grid-cols-2">
                    {[
                      {
                        id: "yes" as const,
                        label: "예, 홈페이지가 열려요",
                        hint: "홈페이지를 연결한 업체를 이어서 확인합니다.",
                      },
                      {
                        id: "no" as const,
                        label: "아니요, 아직 연결하지 않았어요",
                        hint: `${selectedDomainProvider?.label ?? "도메인 구매처"}에서 설정을 진행합니다.`,
                      },
                    ].map((option) => {
                      const selected = websiteConnection === option.id;
                      return (
                        <button
                          key={option.id}
                          type="button"
                          aria-pressed={selected}
                          onClick={() =>
                            persistDomainWizard(
                              websiteConnectionStep,
                              domainProvider,
                              confirmedDnsRows,
                              option.id,
                              option.id === "no" ? "" : websiteHostingProvider,
                            )
                          }
                          className={`min-h-[104px] cursor-pointer rounded-[15px] border px-5 py-4 text-left transition-all ${
                            selected
                              ? "border-[#2f6df6] bg-[#f2f6ff] shadow-[0_8px_22px_rgba(47,109,246,0.1)]"
                              : "border-[#e1e8f3] bg-white hover:border-[#bfd1f5] hover:bg-[#fafcff]"
                          }`}
                        >
                          <span className={`block text-[15px] font-semibold ${selected ? "text-[#2f6df6]" : "text-[#263957]"}`}>{option.label}</span>
                          <span className="mt-2 block text-[12px] leading-5 text-[#7b8ca8]">{option.hint}</span>
                        </button>
                      );
                    })}
                  </div>
                  <div className="mt-7 flex items-center justify-between gap-3">
                    <button type="button" onClick={() => persistDomainWizard(0)} className="h-11 cursor-pointer px-2 text-[13px] font-semibold text-[#6d7f9d]">이전</button>
                    <button
                      type="button"
                      disabled={!websiteConnection}
                      onClick={() => persistDomainWizard(websiteConnection === "yes" ? websiteHostingProviderStep : domainLocationStep)}
                      className="om-btn-primary h-11 min-w-[112px] rounded-[10px] px-5 text-[13px] disabled:cursor-not-allowed disabled:opacity-45"
                    >
                      다음
                    </button>
                  </div>
                </div>
              ) : null}

              {websiteConnection === "yes" && domainWizardStep === websiteHostingProviderStep ? (
                <div>
                  <p className="text-[12px] font-semibold text-[#2f6df6]">홈페이지 연결 위치</p>
                  <h2 className="mt-2 text-[24px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[30px]">홈페이지는 어디에 연결되어 있나요?</h2>
                  <p className="mt-3 text-[13px] leading-6 text-[#6d7f9d]">홈페이지나 쇼핑몰을 만들고 관리할 때 로그인하는 업체를 선택해주세요. 도메인을 구매한 곳과 달라도 괜찮습니다.</p>
                  <div className="mt-6 grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
                    {WEBSITE_HOSTING_PROVIDERS.map((provider) => {
                      const selected = websiteHostingProvider === provider.id;
                      return (
                        <button
                          key={provider.id}
                          type="button"
                          aria-pressed={selected}
                          onClick={() =>
                            persistDomainWizard(
                              websiteHostingProviderStep,
                              domainProvider,
                              confirmedDnsRows,
                              websiteConnection,
                              provider.id,
                            )
                          }
                          className={`min-h-[82px] cursor-pointer rounded-[14px] border px-4 py-3 text-left transition-all ${
                            selected
                              ? "border-[#2f6df6] bg-[#f2f6ff] shadow-[0_8px_22px_rgba(47,109,246,0.1)]"
                              : "border-[#e1e8f3] bg-white hover:border-[#bfd1f5] hover:bg-[#fafcff]"
                          }`}
                        >
                          <span className={`block text-[14px] font-semibold ${selected ? "text-[#2f6df6]" : "text-[#263957]"}`}>{provider.label}</span>
                          <span className="mt-1.5 block text-[11px] leading-4 text-[#7b8ca8]">{provider.hint}</span>
                        </button>
                      );
                    })}
                  </div>
                  <div className="mt-7 flex items-center justify-between gap-3">
                    <button type="button" onClick={() => persistDomainWizard(websiteConnectionStep)} className="h-11 cursor-pointer px-2 text-[13px] font-semibold text-[#6d7f9d]">이전</button>
                    <button type="button" disabled={!websiteHostingProvider} onClick={() => persistDomainWizard(domainLocationStep)} className="om-btn-primary h-11 min-w-[112px] rounded-[10px] px-5 text-[13px] disabled:cursor-not-allowed disabled:opacity-45">다음</button>
                  </div>
                </div>
              ) : null}

              {domainRegistrationStep !== null && domainWizardStep === domainRegistrationStep ? (
                <div>
                  <p className="text-[12px] font-semibold text-[#2f6df6]">대표 주소 만들기</p>
                  <h2 className="mt-2 text-[24px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[30px]">사용할 도메인과 메일 아이디를 확인해주세요</h2>
                  <p className="mt-3 text-[13px] leading-6 text-[#6d7f9d]">`www`, `https://`는 제외하고 구매한 도메인만 입력합니다.</p>
                  <form action={completeMailSetupAction} onSubmit={() => persistDomainWizard(domainRecordStartStep - 1)} className="mt-7">
                    <div className="grid gap-4 sm:grid-cols-2">
                      <label className="block"><span className="mb-2 block text-[13px] font-semibold text-[#4f6284]">구매한 도메인</span><input required type="text" name="domain" value={domain} onChange={(event) => setDomain(event.target.value)} placeholder="예: mybrand.com" className="h-12 w-full rounded-[11px] border border-[#dbe5f7] bg-white px-3.5 text-[14px] text-[#1a2943] outline-none focus:border-[#9fbcfb]" /></label>
                      <label className="block"><span className="mb-2 block text-[13px] font-semibold text-[#4f6284]">@ 앞에 사용할 아이디</span><input required type="text" name="localPart" pattern="^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$" value={localPart} onChange={(event) => setLocalPart(event.target.value)} placeholder="예: contact" className="h-12 w-full rounded-[11px] border border-[#dbe5f7] bg-white px-3.5 text-[14px] text-[#1a2943] outline-none focus:border-[#9fbcfb]" /></label>
                    </div>
                    <DkimKeySizeSelector value={dkimKeySize} onChange={setDkimKeySize} />
                    <div className="mt-5 rounded-[14px] bg-[#f5f8fd] px-4 py-4"><p className="text-[12px] font-semibold text-[#7183a1]">생성될 대표 메일</p><p className="mt-1 break-all text-[19px] font-semibold tracking-[-0.03em] text-[#16233c]">{previewMailbox}</p></div>
                    <div className="mt-7 flex items-center justify-between gap-3"><button type="button" onClick={() => persistDomainWizard(domainLocationStep)} className="h-11 cursor-pointer px-2 text-[13px] font-semibold text-[#6d7f9d]">이전</button><SubmitButton label="저장하고 다음" pendingLabel="저장 중..." className="om-btn-primary h-11 rounded-[10px] px-5 text-[13px]" /></div>
                  </form>
                </div>
              ) : null}

              {domainWizardStep === domainLocationStep ? (
                <div>
                  <p className="text-[12px] font-semibold text-[#2f6df6]">DNS 설정 위치 확인</p>
                  <h2 className="mt-2 text-[24px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[30px]">
                    {websiteConnection === "yes"
                      ? `연결된 ${selectedWebsiteHostingProvider?.label ?? "호스팅사"}에서 설정해주세요`
                      : `${selectedDomainProvider?.label ?? "도메인 구매처"}의 DNS 관리 화면을 열어주세요`}
                  </h2>
                  <p className="mt-3 text-[13px] leading-6 text-[#6d7f9d]">
                    {websiteConnection === "yes"
                      ? `홈페이지 연결에 사용한 ${selectedWebsiteHostingProvider?.label ?? "호스팅사"} 관리자 페이지에 로그인한 뒤 DNS 또는 도메인 설정 메뉴를 찾습니다. 다음부터 보여드리는 값을 그곳에 한 줄씩 추가합니다.`
                      : `홈페이지가 아직 연결되지 않았으므로 ${selectedDomainProvider?.label ?? "도메인 구매처"}의 DNS 관리 화면에 다음 값을 한 줄씩 추가합니다.`}
                  </p>
                  <div className="mt-6 rounded-[18px] border border-[#dce7f8] bg-[linear-gradient(135deg,#f8fbff,#eef4ff)] px-5 py-5">
                    <p className="text-[12px] font-semibold text-[#2f6df6]">{websiteConnection === "yes" ? "설정할 홈페이지 관리자" : "찾아갈 메뉴"}</p>
                    <p className="mt-2 text-[18px] font-semibold text-[#263957]">
                      {websiteConnection === "yes"
                        ? selectedWebsiteHostingProvider?.hint ?? "홈페이지 관리자 · DNS 설정"
                        : selectedDomainProvider?.hint ?? "도메인 관리 · DNS 레코드 관리"}
                    </p>
                    <p className="mt-2 text-[12px] leading-5 text-[#7183a1]">메뉴 이름이 조금 다르다면 `DNS`, `레코드`, `네임서버` 중 DNS 레코드를 추가할 수 있는 화면을 찾으세요.</p>
                  </div>
                  {websiteConnection === "yes" ? (
                    <div className="mt-4 rounded-[14px] border border-[#e1e8f3] bg-[#fbfcff] px-4 py-4 text-[12px] leading-5 text-[#667b9d]">
                      호스팅사 관리자에 DNS 메뉴가 없다면 홈페이지 연결 때 네임서버를 옮기지 않은 경우일 수 있습니다. 이때는 {selectedDomainProvider?.label ?? "도메인 구매처"}의 DNS 관리 화면을 확인하거나 채널톡으로 문의해주세요.
                    </div>
                  ) : null}
                  {domainProvider === "unknown" || (websiteConnection === "yes" && websiteHostingProvider === "unknown") ? <div className="mt-4 rounded-[14px] border border-[#f0dfbf] bg-[#fffaf0] px-4 py-4 text-[12px] leading-5 text-[#80663a]">업체를 찾기 어렵다면 채널톡에 도메인 주소만 보내주세요. 현재 DNS를 관리하는 위치를 함께 확인해드립니다.</div> : null}
                  <div className="mt-7 flex items-center justify-between gap-3">
                    <button type="button" onClick={() => persistDomainWizard(websiteConnection === "yes" ? websiteHostingProviderStep : websiteConnectionStep)} className="h-11 cursor-pointer px-2 text-[13px] font-semibold text-[#6d7f9d]">이전</button>
                    <button type="button" onClick={() => persistDomainWizard(domainRegistrationStep ?? domainRecordStartStep)} className="om-btn-primary h-11 rounded-[10px] px-5 text-[13px]">설정 화면을 열었어요</button>
                  </div>
                </div>
              ) : null}

              {activeDnsRow ? (
                <div>
                  <p className="text-[12px] font-semibold text-[#2f6df6]">DNS 레코드 {activeDnsRowIndex + 1} / {dnsRows.length}</p>
                  <h2 className="mt-2 text-[24px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[30px]">{activeDnsRow.type} 레코드를 추가해주세요</h2>
                  <p className="mt-3 text-[13px] leading-6 text-[#6d7f9d]">아래 항목을 같은 한 줄에 입력합니다. 값은 줄이거나 수정하지 마세요.</p>
                  <div className="mt-6 overflow-hidden rounded-[16px] border border-[#dfe7f3] bg-white">
                    {[["유형", activeDnsRow.type], ["호스트", activeDnsRow.host], ["값", activeDnsRow.value], ["우선순위", activeDnsRow.priorityValue], ["TTL", activeDnsRow.ttl]].map(([label, value]) => {
                      const copyKey = `${activeDnsRow.key}:${label}`;
                      return (
                        <div key={label} className="grid grid-cols-[88px_minmax(0,1fr)_44px] items-stretch border-b border-[#edf1f6] last:border-0 sm:grid-cols-[120px_minmax(0,1fr)_48px]">
                          <span className="bg-[#f8faff] px-3 py-3 text-[12px] font-semibold text-[#7183a1] sm:px-4">{label}</span>
                          <span className="break-all px-3 py-3 text-[13px] leading-5 text-[#263957] sm:px-4">{value}</span>
                          <button type="button" disabled={!value || value === "-"} onClick={() => copyDnsText(copyKey, value)} aria-label={`${label} 복사`} className="inline-flex cursor-pointer items-center justify-center border-l border-[#edf1f6] text-[#2f6df6] transition-colors hover:bg-[#f7faff] disabled:cursor-default disabled:text-[#c4cede]">
                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" className="h-4 w-4" aria-hidden="true"><rect x="8" y="8" width="10" height="10" rx="2" /><path d="M15 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h2" /></svg>
                            <span className="sr-only">{copiedRowKey === copyKey ? "복사됨" : `${label} 복사`}</span>
                          </button>
                        </div>
                      );
                    })}
                  </div>

                  {activeDnsRow.type === "TXT" && activeDnsRow.host.includes("_domainkey") && overview?.dkimEnabled ? (
                    <form action={regenerateMailSetupDkimAction} className="mt-4 rounded-[14px] bg-[#f7faff] px-4 py-4"><DkimKeySizeSelector value={dkimKeySize} onChange={setDkimKeySize} plain /><SubmitButton label="DKIM 키 다시 발급" pendingLabel="발급 중..." className="om-btn-secondary mt-3 h-10 rounded-[10px] px-4 text-[12px]" /></form>
                  ) : null}

                  <label className="mt-5 flex cursor-pointer items-start gap-3 rounded-[13px] bg-[#f5f8fd] px-4 py-3.5"><input type="checkbox" checked={confirmedDnsRows.includes(activeDnsRow.key)} onChange={(event) => { const nextRows = event.target.checked ? [...new Set([...confirmedDnsRows, activeDnsRow.key])] : confirmedDnsRows.filter((key) => key !== activeDnsRow.key); if (event.target.checked) void trackMarketingFunnelEvent("dns_record_confirmed", getDnsRecordFunnelDetail(activeDnsRow, activeDnsRowIndex)); persistDomainWizard(domainWizardStep, domainProvider, nextRows); }} className="mt-0.5 h-4 w-4 accent-[#2f6df6]" /><span className="text-[13px] font-semibold text-[#405575]">이 레코드를 DNS 화면에 저장했습니다.</span></label>
                  <div className="mt-7 flex items-center justify-between gap-3"><button type="button" onClick={() => persistDomainWizard(domainWizardStep - 1)} className="h-11 cursor-pointer px-2 text-[13px] font-semibold text-[#6d7f9d]">이전</button><button type="button" disabled={!confirmedDnsRows.includes(activeDnsRow.key)} onClick={() => persistDomainWizard(domainWizardStep + 1)} className="om-btn-primary h-11 rounded-[10px] px-5 text-[13px] disabled:cursor-not-allowed disabled:opacity-45">다음 레코드</button></div>
                </div>
              ) : null}

              {domainWizardStep === domainVerifyStep ? (
                <div>
                  <p className="text-[12px] font-semibold text-[#2f6df6]">마지막 단계</p>
                  <h2 className="mt-2 text-[24px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[30px]">입력한 DNS 값이 공개되었는지 확인합니다</h2>
                  <p className="mt-3 text-[13px] leading-6 text-[#6d7f9d]">저장 직후에는 아직 반영 중일 수 있습니다. 실패해도 입력값이 맞다면 10~30분 뒤 다시 확인해주세요.</p>
                  <div className="mt-6 rounded-[18px] border border-[#dce7f8] bg-[#f8fbff] px-5 py-5"><div className="flex flex-wrap items-center gap-2"><span className={`om-badge om-badge-lg ${badge.className}`}>{badge.label}</span><span className="om-badge om-badge-lg om-badge-info">{normalizedDomain}</span><span className="om-badge om-badge-lg om-badge-muted">{previewMailbox}</span></div><p className="mt-3 text-[12px] leading-5 text-[#7183a1]">DNS 변경 사항은 서비스에 따라 최대 24시간이 걸릴 수 있습니다.</p></div>
                  {overview && (verificationHelpOpen || overview.status === "failed") ? <div className="mt-4 rounded-[14px] border border-[#f1d9de] bg-[#fffafb] px-4 py-4"><p className="text-[13px] font-semibold text-[#9f4054]">{failedDnsRows.length > 0 ? `${failedDnsRows.map((row) => `${row.type} ${row.host}`).join(", ")} 설정을 다시 확인해주세요.` : "DNS가 아직 공개 조회되지 않습니다."}</p><p className="mt-1 text-[12px] leading-5 text-[#7b6370]">입력값이 맞다면 전파 중일 수 있습니다. 잠시 후 다시 확인하거나 채널톡으로 문의해주세요.</p></div> : null}
                  <form action={verifyMailSetupAction} onSubmit={() => { window.sessionStorage.setItem(verificationAttemptKey, "1"); window.sessionStorage.removeItem(verificationFailureEventKey); void trackMarketingFunnelEvent("dns_verification_attempted"); setVerificationHelpOpen(false); }} className="mt-5"><SubmitButton label="연결 상태 확인" pendingLabel="DNS 확인 중..." disabled={!overview} className="om-btn-primary h-12 w-full rounded-[11px] px-5 text-[14px]" /></form>
                  <div className="mt-3 flex items-center justify-between"><button type="button" onClick={() => persistDomainWizard(domainVerifyStep - 1)} className="h-10 cursor-pointer px-2 text-[13px] font-semibold text-[#6d7f9d]">이전</button><button type="button" onClick={openChannelTalk} className="h-10 cursor-pointer px-2 text-[13px] font-semibold text-[#2f6df6]">채널톡으로 도움받기</button></div>
                </div>
              ) : null}
            </div>

            {domainSetupAssistanceAvailable ? (
              <DomainSetupAssistance
                canRequest={!showDomainForm}
                defaultNotificationEmail={sessionNotificationEmail}
                domain={normalizedDomain}
              />
            ) : null}
          </section>
        )}
      </div>
    </SettingsShell>
  );
}
