import { useCallback, useEffect, useState, type ReactNode } from "react";
import { Search, Plus, Download, MapPin, Building2, User, Phone, X, Clock, FileText, Calendar } from "lucide-react";
import { motion, AnimatePresence } from "motion/react";
import { useLocation } from "react-router-dom";
import {
  checkChannelExpansionDuplicate,
  checkSalesExpansionDuplicate,
  createChannelExpansion,
  createSalesExpansion,
  decodeExpansionMultiValue,
  getExpansionCityOptions,
  getExpansionMeta,
  getExpansionOverview,
  getStoredCurrentUserId,
  updateChannelExpansion,
  updateSalesExpansion,
  type ChannelExpansionContact,
  type ChannelExpansionItem,
  type CreateChannelExpansionPayload,
  type CreateSalesExpansionPayload,
  type ExpansionDictOption,
  type ExpansionFollowUp,
  type SalesExpansionItem,
} from "@/lib/auth";
import { AdaptiveSelect } from "@/components/AdaptiveSelect";
import { useIsMobileViewport } from "@/hooks/useIsMobileViewport";
import { useIsWecomBrowser } from "@/hooks/useIsWecomBrowser";
import { cn } from "@/lib/utils";

type ExpansionItem = SalesExpansionItem | ChannelExpansionItem;
type ExpansionTab = "sales" | "channel";
type SalesCreateField =
  | "employeeNo"
  | "officeName"
  | "candidateName"
  | "mobile"
  | "targetDept"
  | "industry"
  | "title"
  | "intentLevel"
  | "employmentStatus";
type ChannelField =
  | "channelName"
  | "province"
  | "city"
  | "officeAddress"
  | "channelIndustry"
  | "certificationLevel"
  | "annualRevenue"
  | "staffSize"
  | "contactEstablishedDate"
  | "intentLevel"
  | "channelAttribute"
  | "channelAttributeCustom"
  | "internalAttribute"
  | "contacts";
function createEmptyChannelContact(): ChannelExpansionContact {
  return {
    name: "",
    mobile: "",
    title: "",
  };
}

const defaultSalesForm: CreateSalesExpansionPayload = {
  employeeNo: "",
  candidateName: "",
  officeName: "",
  mobile: "",
  industry: "",
  title: "",
  intentLevel: "medium",
  hasDesktopExp: false,
  employmentStatus: "active",
};

const defaultChannelForm: CreateChannelExpansionPayload = {
  channelCode: "",
  channelName: "",
  province: "",
  city: "",
  officeAddress: "",
  channelIndustry: [],
  certificationLevel: "",
  contactEstablishedDate: "",
  intentLevel: "medium",
  hasDesktopExp: false,
  channelAttribute: [],
  channelAttributeCustom: "",
  internalAttribute: [],
  stage: "initial_contact",
  remark: "",
  contacts: [createEmptyChannelContact()],
};

function isOtherOption(option?: ExpansionDictOption) {
  const candidate = `${option?.label ?? ""}${option?.value ?? ""}`.toLowerCase();
  return candidate.includes("其他") || candidate.includes("其它") || candidate.includes("other");
}

function normalizeOptionalText(value?: string) {
  const trimmed = value?.trim();
  return trimmed ? trimmed : undefined;
}

function dedupeExpansionItemsById<T extends { id?: number | string | null }>(items: T[]) {
  const seenIds = new Set<number | string>();
  return items.filter((item) => {
    if (item.id === null || item.id === undefined) {
      return true;
    }
    if (seenIds.has(item.id)) {
      return false;
    }
    seenIds.add(item.id);
    return true;
  });
}

function getFieldInputClass(hasError: boolean) {
  return cn(
    "crm-input-box crm-input-text w-full border bg-white outline-none focus:border-violet-500 focus:ring-1 focus:ring-violet-500 dark:bg-slate-900/50",
    hasError
      ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10"
      : "border-slate-200 dark:border-slate-800",
  );
}

function normalizeExportText(value?: string | number | boolean | null) {
  if (value === null || value === undefined) {
    return "";
  }
  const normalized = String(value).replace(/\r?\n/g, " ").trim();
  if (!normalized || normalized === "无") {
    return "";
  }
  return normalized;
}

function formatExportBoolean(value?: boolean, trueLabel = "是", falseLabel = "否") {
  if (value === null || value === undefined) {
    return "";
  }
  return value ? trueLabel : falseLabel;
}

function formatExportFollowUps(followUps?: ExpansionFollowUp[]) {
  if (!followUps?.length) {
    return "";
  }
  return followUps
    .map((followUp) => {
      const summary = getExpansionFollowUpSummary(followUp);
      const lines = [
        [normalizeExportText(followUp.date), normalizeExportText(followUp.type)].filter(Boolean).join(" "),
        normalizeExportText(summary.visitStartTime) ? `拜访时间：${normalizeExportText(summary.visitStartTime)}` : "",
        normalizeExportText(summary.evaluationContent) ? `沟通内容：${normalizeExportText(summary.evaluationContent)}` : "",
        normalizeExportText(summary.nextPlan) ? `后续规划：${normalizeExportText(summary.nextPlan)}` : "",
      ].filter(Boolean);
      return lines.join("\n");
    })
    .filter(Boolean)
    .join("\n\n");
}

function formatExportFilenameTime(date = new Date()) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  const hours = String(date.getHours()).padStart(2, "0");
  const minutes = String(date.getMinutes()).padStart(2, "0");
  const seconds = String(date.getSeconds()).padStart(2, "0");
  return `${year}${month}${day}_${hours}${minutes}${seconds}`;
}

function downloadExcelFile(filename: string, content: BlobPart) {
  const blob = new Blob([content], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
  const objectUrl = window.URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = objectUrl;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  window.URL.revokeObjectURL(objectUrl);
}

function buildSalesExportHeaders(items: SalesExpansionItem[]) {
  const maxProjects = Math.max(0, ...items.map((item) => item.relatedProjects?.length ?? 0));
  const headers = [
    "工号",
    "姓名",
    "创建人",
    "联系方式",
    "代表处 / 办事处",
    "所属部门",
    "职务",
    "所属行业",
    "合作意向",
    "销售是否在职",
    "销售以前是否做过云桌面项目",
    "跟进项目金额",
  ];

  for (let index = 0; index < maxProjects; index += 1) {
    headers.push(`项目${index + 1}编码`, `项目${index + 1}名称`, `项目${index + 1}金额`);
  }

  headers.push("跟进记录");
  return headers;
}

function buildSalesExportData(items: SalesExpansionItem[]) {
  const maxProjects = Math.max(0, ...items.map((item) => item.relatedProjects?.length ?? 0));

  return items.map((item) => {
    const row = [
      normalizeExportText(item.employeeNo),
      normalizeExportText(item.name),
      normalizeExportText(item.owner),
      normalizeExportText(item.phone),
      normalizeExportText(item.officeName),
      normalizeExportText(item.dept),
      normalizeExportText(item.title),
      normalizeExportText(item.industry),
      normalizeExportText(item.intent),
      item.active === null || item.active === undefined ? "" : item.active ? "是" : "否",
      formatExportBoolean(item.hasExp),
      normalizeExportText(formatRelatedProjectAmount(item.relatedProjects)),
    ];

    for (let index = 0; index < maxProjects; index += 1) {
      const project = item.relatedProjects?.[index];
      row.push(
        normalizeExportText(project?.opportunityCode),
        normalizeExportText(project?.opportunityName),
        project?.amount === null || project?.amount === undefined ? "" : formatAmount(Number(project.amount)),
      );
    }

    row.push(formatExportFollowUps(item.followUps));
    return row;
  });
}

function buildChannelExportHeaders(items: ChannelExpansionItem[]) {
  const maxProjects = Math.max(0, ...items.map((item) => item.relatedProjects?.length ?? 0));
  const maxContacts = Math.max(0, ...items.map((item) => item.contacts?.length ?? 0));
  const headers = [
    "编码",
    "渠道名称",
    "创建人",
    "省份",
    "市",
    "办公地址",
    "认证级别",
    "聚焦行业",
    "渠道属性",
    "新华三内部属性",
    "合作意向",
    "建立联系时间",
    "营收规模",
    "人员规模",
    "以前是否做过云桌面项目",
    "跟进项目金额",
  ];

  for (let index = 0; index < maxProjects; index += 1) {
    headers.push(`项目${index + 1}编码`, `项目${index + 1}名称`, `项目${index + 1}金额`);
  }

  for (let index = 0; index < maxContacts; index += 1) {
    headers.push(`人员${index + 1}姓名`, `人员${index + 1}联系电话`, `人员${index + 1}职位`);
  }

  headers.push("备注说明");
  headers.push("跟进记录");
  return headers;
}

function buildChannelExportData(items: ChannelExpansionItem[]) {
  const maxProjects = Math.max(0, ...items.map((item) => item.relatedProjects?.length ?? 0));
  const maxContacts = Math.max(0, ...items.map((item) => item.contacts?.length ?? 0));

  return items.map((item) => {
    const row = [
      normalizeExportText(item.channelCode),
      normalizeExportText(item.name),
      normalizeExportText(item.owner),
      normalizeExportText(item.province),
      normalizeExportText(item.city),
      normalizeExportText(item.officeAddress),
      normalizeExportText(item.certificationLevel),
      normalizeExportText(item.channelIndustry),
      normalizeExportText(item.channelAttribute),
      normalizeExportText(item.internalAttribute),
      normalizeExportText(item.intent),
      normalizeExportText(item.establishedDate),
      normalizeExportText(item.revenue),
      item.size ? `${item.size}人` : "",
      formatExportBoolean(item.hasDesktopExp),
      normalizeExportText(formatRelatedProjectAmount(item.relatedProjects)),
    ];

    for (let index = 0; index < maxProjects; index += 1) {
      const project = item.relatedProjects?.[index];
      row.push(
        normalizeExportText(project?.opportunityCode),
        normalizeExportText(project?.opportunityName),
        project?.amount === null || project?.amount === undefined ? "" : formatAmount(Number(project.amount)),
      );
    }

    for (let index = 0; index < maxContacts; index += 1) {
      const contact = item.contacts?.[index];
      row.push(
        normalizeExportText(contact?.name),
        normalizeExportText(contact?.mobile),
        normalizeExportText(contact?.title),
      );
    }

    row.push(normalizeExportText(item.notes));
    row.push(formatExportFollowUps(item.followUps));
    return row;
  });
}

function validateSalesCreateForm(form: CreateSalesExpansionPayload) {
  const errors: Partial<Record<SalesCreateField, string>> = {};

  if (!form.employeeNo?.trim()) {
    errors.employeeNo = "请填写工号";
  }
  if (!form.officeName?.trim()) {
    errors.officeName = "请选择代表处 / 办事处";
  }
  if (!form.candidateName?.trim()) {
    errors.candidateName = "请填写姓名";
  }
  if (!form.mobile?.trim()) {
    errors.mobile = "请填写联系方式";
  }
  if (!form.targetDept?.trim()) {
    errors.targetDept = "请填写所属部门";
  }
  if (!form.industry?.trim()) {
    errors.industry = "请选择所属行业";
  }
  if (!form.title?.trim()) {
    errors.title = "请填写职务";
  }
  if (!form.intentLevel?.trim()) {
    errors.intentLevel = "请选择合作意向";
  }
  if (!form.employmentStatus?.trim()) {
    errors.employmentStatus = "请选择销售是否在职";
  }

  return errors;
}

function validateChannelForm(form: CreateChannelExpansionPayload, channelOtherOptionValue?: string) {
  const errors: Partial<Record<ChannelField, string>> = {};
  const invalidContactRows: number[] = [];

  if (!form.channelName?.trim()) {
    errors.channelName = "请填写渠道名称";
  }
  if (!form.province?.trim()) {
    errors.province = "请选择省份";
  }
  if (!form.city?.trim()) {
    errors.city = "请选择市";
  }
  if (!form.officeAddress?.trim()) {
    errors.officeAddress = "请填写办公地址";
  }
  if (!form.certificationLevel?.trim()) {
    errors.certificationLevel = "请选择认证级别";
  }
  if ((form.channelIndustry?.length ?? 0) <= 0) {
    errors.channelIndustry = "请选择聚焦行业";
  }
  if (!form.annualRevenue || form.annualRevenue <= 0) {
    errors.annualRevenue = "请填写年营收";
  }
  if (!form.staffSize || form.staffSize <= 0) {
    errors.staffSize = "请填写人员规模";
  }
  if (!form.contactEstablishedDate?.trim()) {
    errors.contactEstablishedDate = "请选择建立联系时间";
  }
  if (!form.intentLevel?.trim()) {
    errors.intentLevel = "请选择合作意向";
  }
  if ((form.channelAttribute?.length ?? 0) <= 0) {
    errors.channelAttribute = "请选择渠道属性";
  }
  if (channelOtherOptionValue && form.channelAttribute?.includes(channelOtherOptionValue) && !form.channelAttributeCustom?.trim()) {
    errors.channelAttributeCustom = "请选择“其它”后请补充具体渠道属性";
  }
  if ((form.internalAttribute?.length ?? 0) <= 0) {
    errors.internalAttribute = "请选择新华三内部属性";
  }

  const contacts = form.contacts ?? [];
  if (contacts.length <= 0) {
    errors.contacts = "请至少填写一位渠道联系人";
    invalidContactRows.push(0);
  } else {
    contacts.forEach((contact, index) => {
      const hasName = Boolean(contact.name?.trim());
      const hasMobile = Boolean(contact.mobile?.trim());
      const hasTitle = Boolean(contact.title?.trim());
      if (!hasName || !hasMobile || !hasTitle) {
        invalidContactRows.push(index);
      }
    });
    if (invalidContactRows.length > 0) {
      errors.contacts = "请完整填写每位渠道联系人的姓名、联系电话和职位";
    }
  }

  return { errors, invalidContactRows };
}

function normalizeSalesPayload(payload: CreateSalesExpansionPayload): CreateSalesExpansionPayload {
  return {
    employeeNo: payload.employeeNo.trim(),
    candidateName: payload.candidateName.trim(),
    officeName: normalizeOptionalText(payload.officeName),
    mobile: normalizeOptionalText(payload.mobile),
    email: normalizeOptionalText(payload.email),
    targetDept: normalizeOptionalText(payload.targetDept),
    industry: normalizeOptionalText(payload.industry),
    title: normalizeOptionalText(payload.title),
    intentLevel: normalizeOptionalText(payload.intentLevel) ?? "medium",
    stage: normalizeOptionalText(payload.stage) ?? "initial_contact",
    hasDesktopExp: Boolean(payload.hasDesktopExp),
    inProgress: payload.inProgress ?? true,
    employmentStatus: normalizeOptionalText(payload.employmentStatus) ?? "active",
    expectedJoinDate: normalizeOptionalText(payload.expectedJoinDate),
    remark: normalizeOptionalText(payload.remark),
  };
}

function normalizeChannelPayload(payload: CreateChannelExpansionPayload): CreateChannelExpansionPayload {
  return {
    channelCode: normalizeOptionalText(payload.channelCode),
    officeAddress: normalizeOptionalText(payload.officeAddress),
    channelIndustry: Array.from(new Set((payload.channelIndustry ?? []).map((value) => value?.trim()).filter((value): value is string => Boolean(value)))),
    channelName: payload.channelName.trim(),
    province: normalizeOptionalText(payload.province),
    city: normalizeOptionalText(payload.city),
    certificationLevel: normalizeOptionalText(payload.certificationLevel),
    annualRevenue: payload.annualRevenue || undefined,
    staffSize: payload.staffSize || undefined,
    contactEstablishedDate: normalizeOptionalText(payload.contactEstablishedDate),
    intentLevel: normalizeOptionalText(payload.intentLevel) ?? "medium",
    hasDesktopExp: Boolean(payload.hasDesktopExp),
    channelAttribute: Array.from(new Set((payload.channelAttribute ?? []).map((value) => value?.trim()).filter((value): value is string => Boolean(value)))),
    channelAttributeCustom: normalizeOptionalText(payload.channelAttributeCustom),
    internalAttribute: Array.from(new Set((payload.internalAttribute ?? []).map((value) => value?.trim()).filter((value): value is string => Boolean(value)))),
    stage: normalizeOptionalText(payload.stage) ?? "initial_contact",
    remark: normalizeOptionalText(payload.remark),
    contacts: (payload.contacts ?? [])
      .map((contact) => ({
        name: normalizeOptionalText(contact.name),
        mobile: normalizeOptionalText(contact.mobile),
        title: normalizeOptionalText(contact.title),
      }))
      .filter((contact) => contact.name || contact.mobile || contact.title),
  };
}

function normalizeOptionValue(rawValue: string | undefined, options: ExpansionDictOption[]) {
  const trimmed = rawValue?.trim();
  if (!trimmed) {
    return "";
  }

  const matched = options.find((option) => option.value === trimmed || option.label === trimmed);
  return matched?.value ?? trimmed;
}

function normalizeMultiOptionValues(rawValue: string | undefined, options: ExpansionDictOption[]) {
  const { values } = decodeExpansionMultiValue(rawValue);
  return Array.from(new Set(values.map((value) => normalizeOptionValue(value, options)).filter(Boolean)));
}

function ModalShell({
  title,
  subtitle,
  onClose,
  children,
  footer,
}: {
  title: string;
  subtitle: string;
  onClose: () => void;
  children: ReactNode;
  footer: ReactNode;
}) {
  const isMobileViewport = useIsMobileViewport();
  const isWecomBrowser = useIsWecomBrowser();
  const disableMobileMotion = isMobileViewport || isWecomBrowser;

  return (
    <>
      <motion.div
        initial={disableMobileMotion ? false : { opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={disableMobileMotion ? undefined : { opacity: 0 }}
        onClick={onClose}
        className={cn("fixed inset-0 z-[70] bg-slate-900/35 dark:bg-slate-950/70", !disableMobileMotion && "backdrop-blur-sm")}
      />
      <motion.div
        initial={disableMobileMotion ? false : { opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        exit={disableMobileMotion ? undefined : { opacity: 0, y: 20 }}
        transition={disableMobileMotion ? { duration: 0 } : undefined}
        className="fixed inset-0 z-[80] px-0 pb-0 pt-[env(safe-area-inset-top)] sm:p-6"
      >
        <div className="mx-auto flex h-[calc(100dvh-env(safe-area-inset-top))] w-full items-end sm:h-full sm:max-w-3xl sm:items-center">
          <div className="flex h-[92dvh] w-full flex-col overflow-hidden rounded-t-3xl border border-slate-200 bg-white shadow-2xl dark:border-slate-800 dark:bg-slate-900 sm:h-full sm:rounded-3xl">
            <div className="flex items-center justify-between border-b border-slate-100 px-5 py-4 dark:border-slate-800 sm:px-6">
              <div>
                <h2 className="text-base font-semibold text-slate-900 dark:text-white sm:text-lg">{title}</h2>
                <p className="mt-1 text-xs leading-5 text-slate-500 dark:text-slate-400">{subtitle}</p>
              </div>
              <button onClick={onClose} className="rounded-full p-2 text-slate-400 transition-colors hover:bg-slate-100 dark:hover:bg-slate-800">
                <X className="h-5 w-5" />
              </button>
            </div>
            <div className="flex-1 overflow-y-auto px-5 py-5 sm:px-6">{children}</div>
            <div className="border-t border-slate-100 px-5 pb-[calc(1rem+env(safe-area-inset-bottom))] pt-4 dark:border-slate-800 sm:px-6 sm:pb-4">{footer}</div>
          </div>
        </div>
      </motion.div>
    </>
  );
}

function DetailItem({
  label,
  value,
  icon,
  className = "",
}: {
  label: string;
  value: ReactNode;
  icon?: ReactNode;
  className?: string;
}) {
  return (
    <div className={`crm-detail-item ${className}`.trim()}>
      <p className="crm-detail-label">
        {icon}
        {label}
      </p>
      <div className="crm-detail-value">{value}</div>
    </div>
  );
}

function RequiredMark() {
  return <span className="ml-1 text-rose-500">*</span>;
}

export default function Expansion() {
  const currentUserId = getStoredCurrentUserId();
  const location = useLocation();
  const isMobileViewport = useIsMobileViewport();
  const isWecomBrowser = useIsWecomBrowser();
  const disableMobileMotion = isMobileViewport || isWecomBrowser;
  const [activeTab, setActiveTab] = useState<ExpansionTab>("sales");
  const [selectedItem, setSelectedItem] = useState<ExpansionItem | null>(null);
  const [keyword, setKeyword] = useState("");
  const [salesData, setSalesData] = useState<SalesExpansionItem[]>([]);
  const [channelData, setChannelData] = useState<ChannelExpansionItem[]>([]);
  const [officeOptions, setOfficeOptions] = useState<ExpansionDictOption[]>([]);
  const [industryOptions, setIndustryOptions] = useState<ExpansionDictOption[]>([]);
  const [provinceOptions, setProvinceOptions] = useState<ExpansionDictOption[]>([]);
  const [certificationLevelOptions, setCertificationLevelOptions] = useState<ExpansionDictOption[]>([]);
  const [createCityOptions, setCreateCityOptions] = useState<ExpansionDictOption[]>([]);
  const [editCityOptions, setEditCityOptions] = useState<ExpansionDictOption[]>([]);
  const [channelAttributeOptions, setChannelAttributeOptions] = useState<ExpansionDictOption[]>([]);
  const [internalAttributeOptions, setInternalAttributeOptions] = useState<ExpansionDictOption[]>([]);
  const [nextChannelCode, setNextChannelCode] = useState("");
  const channelOtherOptionValue = channelAttributeOptions.find(isOtherOption)?.value ?? "";
  const [refreshTick, setRefreshTick] = useState(0);

  const [createOpen, setCreateOpen] = useState(false);
  const [editOpen, setEditOpen] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const [exporting, setExporting] = useState(false);
  const [salesDuplicateChecking, setSalesDuplicateChecking] = useState(false);
  const [channelDuplicateChecking, setChannelDuplicateChecking] = useState(false);
  const [createError, setCreateError] = useState("");
  const [editError, setEditError] = useState("");
  const [exportError, setExportError] = useState("");
  const [salesDuplicateMessage, setSalesDuplicateMessage] = useState("");
  const [channelDuplicateMessage, setChannelDuplicateMessage] = useState("");
  const [salesCreateFieldErrors, setSalesCreateFieldErrors] = useState<Partial<Record<SalesCreateField, string>>>({});
  const [salesEditFieldErrors, setSalesEditFieldErrors] = useState<Partial<Record<SalesCreateField, string>>>({});
  const [channelCreateFieldErrors, setChannelCreateFieldErrors] = useState<Partial<Record<ChannelField, string>>>({});
  const [channelEditFieldErrors, setChannelEditFieldErrors] = useState<Partial<Record<ChannelField, string>>>({});
  const [invalidCreateChannelContactRows, setInvalidCreateChannelContactRows] = useState<number[]>([]);
  const [invalidEditChannelContactRows, setInvalidEditChannelContactRows] = useState<number[]>([]);
  const [salesDetailTab, setSalesDetailTab] = useState<"projects" | "followups">("projects");
  const [channelDetailTab, setChannelDetailTab] = useState<"projects" | "contacts" | "followups">("projects");
  const canEditSelectedItem = Boolean(selectedItem && currentUserId !== undefined && selectedItem.ownerUserId === currentUserId);

  const [salesForm, setSalesForm] = useState<CreateSalesExpansionPayload>(defaultSalesForm);
  const [channelForm, setChannelForm] = useState<CreateChannelExpansionPayload>(defaultChannelForm);
  const [editSalesForm, setEditSalesForm] = useState<CreateSalesExpansionPayload>(defaultSalesForm);
  const [editChannelForm, setEditChannelForm] = useState<CreateChannelExpansionPayload>(defaultChannelForm);
  const hasForegroundModal = createOpen || editOpen;

  const loadMeta = useCallback(async () => {
    const data = await getExpansionMeta();
    setOfficeOptions(data.officeOptions ?? []);
    setIndustryOptions(data.industryOptions ?? []);
    setProvinceOptions(data.provinceOptions ?? []);
    setCertificationLevelOptions(data.certificationLevelOptions ?? []);
    setChannelAttributeOptions(data.channelAttributeOptions ?? []);
    setInternalAttributeOptions(data.internalAttributeOptions ?? []);
    setNextChannelCode(data.nextChannelCode ?? "");
    return data;
  }, []);

  const loadCityOptions = useCallback(async (provinceName?: string, isEdit = false) => {
    const setter = isEdit ? setEditCityOptions : setCreateCityOptions;
    const normalizedProvinceName = provinceName?.trim();
    if (!normalizedProvinceName) {
      setter([]);
      return [];
    }

    try {
      const options = await getExpansionCityOptions(normalizedProvinceName);
      setter(options ?? []);
      return options ?? [];
    } catch {
      setter([]);
      return [];
    }
  }, []);

  useEffect(() => {
    const requestedTab = (location.state as { tab?: ExpansionTab } | null)?.tab;
    if (requestedTab === "sales" || requestedTab === "channel") {
      setActiveTab(requestedTab);
    }
  }, [location.state]);

  useEffect(() => {
    let cancelled = false;

    async function loadMetaOptions() {
      try {
        const data = await loadMeta();
        if (!cancelled) {
          setOfficeOptions(data.officeOptions ?? []);
          setIndustryOptions(data.industryOptions ?? []);
          setProvinceOptions(data.provinceOptions ?? []);
          setCertificationLevelOptions(data.certificationLevelOptions ?? []);
          setChannelAttributeOptions(data.channelAttributeOptions ?? []);
          setInternalAttributeOptions(data.internalAttributeOptions ?? []);
          setNextChannelCode(data.nextChannelCode ?? "");
        }
      } catch {
        if (!cancelled) {
          setOfficeOptions([]);
          setIndustryOptions([]);
          setProvinceOptions([]);
          setCertificationLevelOptions([]);
          setChannelAttributeOptions([]);
          setInternalAttributeOptions([]);
          setNextChannelCode("");
        }
      }
    }

    void loadMetaOptions();

    return () => {
      cancelled = true;
    };
  }, [loadMeta]);

  useEffect(() => {
    let cancelled = false;

    async function loadExpansionData() {
      try {
        const data = await getExpansionOverview(keyword);
        if (cancelled) {
          return;
        }

        setSalesData(dedupeExpansionItemsById(data.salesItems ?? []));
        setChannelData(dedupeExpansionItemsById(data.channelItems ?? []));
        setSelectedItem(null);
      } catch {
        if (!cancelled) {
          setSalesData([]);
          setChannelData([]);
          setSelectedItem(null);
        }
      }
    }

    void loadExpansionData();

    return () => {
      cancelled = true;
    };
  }, [keyword, refreshTick]);

  const followUpRecords: ExpansionFollowUp[] = selectedItem?.followUps ?? [];

  useEffect(() => {
    if (selectedItem?.type === "sales") {
      setSalesDetailTab("projects");
    } else if (selectedItem?.type === "channel") {
      setChannelDetailTab("projects");
    }
  }, [selectedItem]);

  useEffect(() => {
    if (!createOpen || activeTab !== "sales") {
      setSalesDuplicateChecking(false);
      return;
    }

    const normalizedEmployeeNo = salesForm.employeeNo.trim();
    if (!normalizedEmployeeNo) {
      setSalesDuplicateChecking(false);
      setSalesDuplicateMessage("");
      return;
    }

    let cancelled = false;
    const timer = window.setTimeout(async () => {
      setSalesDuplicateChecking(true);
      try {
        const result = await checkSalesExpansionDuplicate(normalizedEmployeeNo);
        if (!cancelled) {
          setSalesDuplicateMessage(result.duplicated ? result.message || "工号重复，请确认该人员是否已存在！" : "");
        }
      } catch {
        if (!cancelled) {
          setSalesDuplicateMessage("");
        }
      } finally {
        if (!cancelled) {
          setSalesDuplicateChecking(false);
        }
      }
    }, 400);

    return () => {
      cancelled = true;
      window.clearTimeout(timer);
    };
  }, [activeTab, createOpen, salesForm.employeeNo]);

  useEffect(() => {
    if (!createOpen || activeTab !== "channel") {
      setChannelDuplicateChecking(false);
      return;
    }

    const normalizedChannelName = channelForm.channelName.trim();
    if (!normalizedChannelName) {
      setChannelDuplicateChecking(false);
      setChannelDuplicateMessage("");
      return;
    }

    let cancelled = false;
    const timer = window.setTimeout(async () => {
      setChannelDuplicateChecking(true);
      try {
        const result = await checkChannelExpansionDuplicate(normalizedChannelName);
        if (!cancelled) {
          setChannelDuplicateMessage(result.duplicated ? result.message || "渠道重复，请确认该渠道是否已存在！" : "");
        }
      } catch {
        if (!cancelled) {
          setChannelDuplicateMessage("");
        }
      } finally {
        if (!cancelled) {
          setChannelDuplicateChecking(false);
        }
      }
    }, 400);

    return () => {
      cancelled = true;
      window.clearTimeout(timer);
    };
  }, [activeTab, channelForm.channelName, createOpen]);

  const handleSalesChange = <K extends keyof CreateSalesExpansionPayload>(key: K, value: CreateSalesExpansionPayload[K]) => {
    setSalesForm((current) => ({ ...current, [key]: value }));
    if (key === "employeeNo") {
      setSalesDuplicateMessage("");
      setSalesDuplicateChecking(false);
    }
    if (key in salesCreateFieldErrors) {
      setSalesCreateFieldErrors((current) => {
        const next = { ...current };
        delete next[key as SalesCreateField];
        return next;
      });
    }
  };

  const handleChannelChange = <K extends keyof CreateChannelExpansionPayload>(key: K, value: CreateChannelExpansionPayload[K]) => {
    setChannelForm((current) => ({ ...current, [key]: value }));
    if (key === "channelName") {
      setChannelDuplicateMessage("");
      setChannelDuplicateChecking(false);
    }
    if (key in channelCreateFieldErrors) {
      setChannelCreateFieldErrors((current) => {
        const next = { ...current };
        delete next[key as ChannelField];
        return next;
      });
    }
  };

  const handleEditSalesChange = <K extends keyof CreateSalesExpansionPayload>(key: K, value: CreateSalesExpansionPayload[K]) => {
    setEditSalesForm((current) => ({ ...current, [key]: value }));
    if (key in salesEditFieldErrors) {
      setSalesEditFieldErrors((current) => {
        const next = { ...current };
        delete next[key as SalesCreateField];
        return next;
      });
    }
  };

  const handleEditChannelChange = <K extends keyof CreateChannelExpansionPayload>(key: K, value: CreateChannelExpansionPayload[K]) => {
    setEditChannelForm((current) => ({ ...current, [key]: value }));
    if (key in channelEditFieldErrors) {
      setChannelEditFieldErrors((current) => {
        const next = { ...current };
        delete next[key as ChannelField];
        return next;
      });
    }
  };

  const handleChannelContactChange = (index: number, key: keyof ChannelExpansionContact, value: string, isEdit = false) => {
    const setter = isEdit ? setEditChannelForm : setChannelForm;
    setter((current) => {
      const nextContacts = [...(current.contacts ?? [])];
      const target = { ...(nextContacts[index] ?? createEmptyChannelContact()), [key]: value };
      nextContacts[index] = target;
      return { ...current, contacts: nextContacts };
    });
    if (isEdit) {
      setChannelEditFieldErrors((current) => {
        if (!current.contacts) {
          return current;
        }
        const next = { ...current };
        delete next.contacts;
        return next;
      });
      setInvalidEditChannelContactRows((current) => current.filter((rowIndex) => rowIndex !== index));
      return;
    }
    setChannelCreateFieldErrors((current) => {
      if (!current.contacts) {
        return current;
      }
      const next = { ...current };
      delete next.contacts;
      return next;
    });
    setInvalidCreateChannelContactRows((current) => current.filter((rowIndex) => rowIndex !== index));
  };

  const addChannelContact = (isEdit = false) => {
    const setter = isEdit ? setEditChannelForm : setChannelForm;
    setter((current) => ({
      ...current,
      contacts: [...(current.contacts ?? []), createEmptyChannelContact()],
    }));
  };

  const removeChannelContact = (index: number, isEdit = false) => {
    const setter = isEdit ? setEditChannelForm : setChannelForm;
    setter((current) => {
      const currentContacts = current.contacts ?? [];
      const nextContacts = currentContacts.filter((_, contactIndex) => contactIndex !== index);
      return {
        ...current,
        contacts: nextContacts.length > 0 ? nextContacts : [createEmptyChannelContact()],
      };
    });
  };

  const resetCreateState = () => {
    setCreateOpen(false);
    setCreateError("");
    setSalesDuplicateChecking(false);
    setChannelDuplicateChecking(false);
    setSalesDuplicateMessage("");
    setChannelDuplicateMessage("");
    setSalesCreateFieldErrors({});
    setChannelCreateFieldErrors({});
    setInvalidCreateChannelContactRows([]);
    setSalesForm(defaultSalesForm);
    setChannelForm(defaultChannelForm);
    setCreateCityOptions([]);
  };

  const resetEditState = () => {
    setEditOpen(false);
    setEditError("");
    setSalesEditFieldErrors({});
    setChannelEditFieldErrors({});
    setInvalidEditChannelContactRows([]);
    setEditSalesForm(defaultSalesForm);
    setEditChannelForm(defaultChannelForm);
    setEditCityOptions([]);
  };

  const handleOpenCreate = async () => {
    setCreateError("");
    setSalesCreateFieldErrors({});
    setChannelCreateFieldErrors({});
    setInvalidCreateChannelContactRows([]);
    try {
      await loadMeta();
    } catch {}
    setCreateCityOptions([]);
    setCreateOpen(true);
  };

  const handleOpenEdit = async () => {
    if (!selectedItem) {
      return;
    }
    if (!canEditSelectedItem) {
      return;
    }

    setEditError("");
    let latestIndustryOptions = industryOptions;
    let latestCertificationLevelOptions = certificationLevelOptions;
    try {
      const meta = await loadMeta();
      latestIndustryOptions = meta.industryOptions ?? [];
      latestCertificationLevelOptions = meta.certificationLevelOptions ?? [];
    } catch {}

    if (selectedItem.type === "sales") {
      setSalesEditFieldErrors({});
      setEditSalesForm({
        employeeNo: selectedItem.employeeNo === "无" ? "" : selectedItem.employeeNo ?? "",
        candidateName: selectedItem.name ?? "",
        officeName: selectedItem.officeCode ?? "",
        mobile: selectedItem.phone === "无" ? "" : selectedItem.phone ?? "",
        targetDept: selectedItem.dept === "无" ? "" : selectedItem.dept ?? selectedItem.targetDept ?? "",
        industry: selectedItem.industryCode ?? "",
        title: selectedItem.title === "无" ? "" : selectedItem.title ?? "",
        intentLevel: selectedItem.intentLevel ?? "medium",
        hasDesktopExp: Boolean(selectedItem.hasExp),
        employmentStatus: selectedItem.active ? "active" : "left",
      });
    } else {
      const parsedChannelAttributes = decodeExpansionMultiValue(selectedItem.channelAttributeCode);
      const parsedInternalAttributes = decodeExpansionMultiValue(selectedItem.internalAttributeCode);
      const normalizedProvinceName = selectedItem.province === "无" ? "" : selectedItem.province ?? "";
      const normalizedCityName = selectedItem.city === "无" ? "" : selectedItem.city ?? "";
      setChannelEditFieldErrors({});
      setInvalidEditChannelContactRows([]);
      setEditChannelForm({
        channelCode: selectedItem.channelCode ?? "",
        channelName: selectedItem.name ?? "",
        province: normalizedProvinceName,
        city: normalizedCityName,
        officeAddress: selectedItem.officeAddress === "无" ? "" : selectedItem.officeAddress ?? "",
        channelIndustry: normalizeMultiOptionValues(
          selectedItem.channelIndustryCode ?? (selectedItem.channelIndustry === "无" ? "" : selectedItem.channelIndustry),
          latestIndustryOptions,
        ),
        certificationLevel: normalizeOptionValue(
          selectedItem.certificationLevel === "无" ? "" : selectedItem.certificationLevel,
          latestCertificationLevelOptions,
        ) || "",
        annualRevenue: selectedItem.annualRevenue ? Number(selectedItem.annualRevenue) : undefined,
        staffSize: selectedItem.size ?? undefined,
        contactEstablishedDate: selectedItem.establishedDate === "无" ? "" : selectedItem.establishedDate ?? "",
        intentLevel: selectedItem.intentLevel ?? "medium",
        hasDesktopExp: Boolean(selectedItem.hasDesktopExp),
        channelAttribute: parsedChannelAttributes.values,
        channelAttributeCustom: parsedChannelAttributes.customText,
        internalAttribute: parsedInternalAttributes.values,
        stage: selectedItem.stageCode ?? "initial_contact",
        remark: selectedItem.notes === "无" ? "" : selectedItem.notes ?? "",
        contacts: (selectedItem.contacts?.length ?? 0) > 0
          ? selectedItem.contacts?.map((contact) => ({
              name: contact.name === "无" ? "" : contact.name ?? "",
              mobile: contact.mobile === "无" ? "" : contact.mobile ?? "",
              title: contact.title === "无" ? "" : contact.title ?? "",
            }))
          : [createEmptyChannelContact()],
      });
      void loadCityOptions(normalizedProvinceName, true);
    }
    setEditOpen(true);
  };

  const handleCreateSubmit = async () => {
    if (submitting) {
      return;
    }

    setCreateError("");
    if (activeTab === "sales") {
      const validationErrors = validateSalesCreateForm(salesForm);
      if (Object.keys(validationErrors).length > 0) {
        setSalesCreateFieldErrors(validationErrors);
        setCreateError("请先完整填写销售人员拓展必填字段");
        return;
      }
    } else {
      const { errors: validationErrors, invalidContactRows } = validateChannelForm(channelForm, channelOtherOptionValue);
      if (Object.keys(validationErrors).length > 0) {
        setChannelCreateFieldErrors(validationErrors);
        setInvalidCreateChannelContactRows(invalidContactRows);
        setCreateError("请先完整填写渠道拓展必填字段");
        return;
      }
    }

    if (activeTab === "sales") {
      const duplicateResult = await checkSalesExpansionDuplicate(salesForm.employeeNo.trim());
      if (duplicateResult.duplicated) {
        const duplicateMessage = duplicateResult.message || "工号重复，请确认该人员是否已存在！";
        setSalesDuplicateMessage(duplicateMessage);
        setSalesCreateFieldErrors((current) => ({ ...current, employeeNo: duplicateMessage }));
        setCreateError(duplicateMessage);
        return;
      }
    } else {
      const duplicateResult = await checkChannelExpansionDuplicate(channelForm.channelName.trim());
      if (duplicateResult.duplicated) {
        const duplicateMessage = duplicateResult.message || "渠道重复，请确认该渠道是否已存在！";
        setChannelDuplicateMessage(duplicateMessage);
        setChannelCreateFieldErrors((current) => ({ ...current, channelName: duplicateMessage }));
        setCreateError(duplicateMessage);
        return;
      }
    }

    setSubmitting(true);

    try {
      if (activeTab === "sales") {
        await createSalesExpansion(normalizeSalesPayload(salesForm));
      } else {
        await createChannelExpansion(normalizeChannelPayload(channelForm));
      }

      resetCreateState();
      setRefreshTick((current) => current + 1);
    } catch (error) {
      setCreateError(error instanceof Error ? error.message : "新增失败");
    } finally {
      setSubmitting(false);
    }
  };

  const handleEditSubmit = async () => {
    if (!selectedItem || submitting) {
      return;
    }
    if (!canEditSelectedItem) {
      setEditError("仅可编辑本人创建的数据");
      return;
    }

    setEditError("");
    if (selectedItem.type === "sales") {
      const validationErrors = validateSalesCreateForm(editSalesForm);
      if (Object.keys(validationErrors).length > 0) {
        setSalesEditFieldErrors(validationErrors);
        setEditError("请先完整填写销售人员拓展必填字段");
        return;
      }
    } else {
      const { errors: validationErrors, invalidContactRows } = validateChannelForm(editChannelForm, channelOtherOptionValue);
      if (Object.keys(validationErrors).length > 0) {
        setChannelEditFieldErrors(validationErrors);
        setInvalidEditChannelContactRows(invalidContactRows);
        setEditError("请先完整填写渠道拓展必填字段");
        return;
      }
    }

    setSubmitting(true);

    try {
      if (selectedItem.type === "sales") {
        await updateSalesExpansion(selectedItem.id, normalizeSalesPayload(editSalesForm));
      } else {
        await updateChannelExpansion(selectedItem.id, normalizeChannelPayload(editChannelForm));
      }

      resetEditState();
      setSelectedItem(null);
      setRefreshTick((current) => current + 1);
    } catch (error) {
      setEditError(error instanceof Error ? error.message : "编辑失败");
    } finally {
      setSubmitting(false);
    }
  };

  const renderEmpty = () => (
    <div className="crm-empty-panel">
      暂无拓展数据，先新增一条试试。
    </div>
  );

  const renderFollowUpTimeline = () => {
    if (followUpRecords.length <= 0) {
      return (
        <div className="crm-empty-panel">
          暂无跟进记录
        </div>
      );
    }

    return (
      <div className="relative space-y-6 border-l-2 border-slate-100 pl-4 dark:border-slate-800">
        {followUpRecords.map((record) => {
          const summary = getExpansionFollowUpSummary(record);
          return (
          <div key={record.id} className="relative">
            <div className="absolute -left-[21px] mt-1.5 h-2.5 w-2.5 rounded-full bg-violet-500 ring-4 ring-white dark:ring-slate-900" />
            <div className="rounded-xl border border-slate-100 bg-slate-50/50 p-4 dark:border-slate-800 dark:bg-slate-800/20">
              <div className="grid grid-cols-1 gap-3 rounded-xl border border-amber-200 bg-amber-50 p-3 text-sm dark:border-amber-500/20 dark:bg-amber-500/10 sm:grid-cols-3">
                <div><p className="mb-1 text-xs text-amber-700 dark:text-amber-300">拜访时间</p><p className="break-anywhere font-medium text-slate-900 dark:text-white">{summary.visitStartTime}</p></div>
                <div><p className="mb-1 text-xs text-amber-700 dark:text-amber-300">沟通内容</p><p className="break-anywhere font-medium text-slate-900 dark:text-white">{summary.evaluationContent}</p></div>
                <div><p className="mb-1 text-xs text-amber-700 dark:text-amber-300">后续规划</p><p className="break-anywhere font-medium text-slate-900 dark:text-white">{summary.nextPlan}</p></div>
              </div>
              <p className="mt-2 text-xs text-slate-400">跟进人: {record.user || "无"}<span className="ml-3">{record.date || "无"}</span></p>
            </div>
          </div>
        )})}
      </div>
    );
  };

  const handleTabChange = (tab: ExpansionTab) => {
    setActiveTab(tab);
    setSelectedItem(null);
    setExportError("");
  };

  const handleExport = async () => {
    if (exporting) {
      return;
    }

    const isSalesTab = activeTab === "sales";
    const items = isSalesTab ? salesData : channelData;
    if (items.length <= 0) {
      setExportError(`当前${isSalesTab ? "销售人员拓展" : "渠道拓展"}暂无可导出数据`);
      return;
    }

    setExporting(true);
    setExportError("");

    try {
      const ExcelJS = await import("exceljs");
      const workbook = new ExcelJS.Workbook();
      const worksheet = workbook.addWorksheet(isSalesTab ? "销售人员拓展" : "渠道拓展");
      const headers = isSalesTab ? buildSalesExportHeaders(salesData) : buildChannelExportHeaders(channelData);
      const rows = isSalesTab ? buildSalesExportData(salesData) : buildChannelExportData(channelData);

      worksheet.addRow(headers);
      rows.forEach((row) => {
        worksheet.addRow(row);
      });

      worksheet.views = [{ state: "frozen", ySplit: 1 }];
      const followUpColumnIndex = headers.indexOf("跟进记录") + 1;
      worksheet.getRow(1).height = 24;
      worksheet.getRow(1).font = { bold: true };
      worksheet.getRow(1).alignment = { vertical: "middle", horizontal: "center" };

      headers.forEach((header, index) => {
        const column = worksheet.getColumn(index + 1);
        if (header === "跟进记录") {
          column.width = 42;
        } else if (header.includes("办公地址") || header.includes("备注")) {
          column.width = 24;
        } else if (header.includes("项目") && header.includes("名称")) {
          column.width = 24;
        } else if (header.includes("渠道属性") || header.includes("内部属性") || header.includes("聚焦行业")) {
          column.width = 18;
        } else {
          column.width = 16;
        }
      });

      worksheet.eachRow((row, rowNumber) => {
        row.eachCell((cell, columnNumber) => {
          cell.border = {
            top: { style: "thin", color: { argb: "FFE2E8F0" } },
            left: { style: "thin", color: { argb: "FFE2E8F0" } },
            bottom: { style: "thin", color: { argb: "FFE2E8F0" } },
            right: { style: "thin", color: { argb: "FFE2E8F0" } },
          };
          cell.alignment = {
            vertical: "top",
            horizontal: rowNumber === 1 ? "center" : "left",
            wrapText: headers[columnNumber - 1] === "跟进记录",
          };
        });
        if (rowNumber > 1 && followUpColumnIndex > 0) {
          const followUpText = normalizeExportText(row.getCell(followUpColumnIndex).value as string | null | undefined);
          const lineCount = followUpText ? followUpText.split("\n").length : 1;
          row.height = Math.max(22, lineCount * 16);
        }
      });

      const buffer = await workbook.xlsx.writeBuffer();
      const filename = `${isSalesTab ? "销售人员拓展" : "渠道拓展"}_${formatExportFilenameTime()}.xlsx`;
      downloadExcelFile(filename, buffer);
    } catch (error) {
      setExportError(error instanceof Error ? error.message : "导出失败，请稍后重试");
    } finally {
      setExporting(false);
    }
  };

  const renderSalesForm = (
    form: CreateSalesExpansionPayload,
    onChange: <K extends keyof CreateSalesExpansionPayload>(key: K, value: CreateSalesExpansionPayload[K]) => void,
    fieldErrors?: Partial<Record<SalesCreateField, string>>,
    isEdit = false,
  ) => (
    <div className="crm-form-grid">
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">工号<RequiredMark /></span>
        <input value={form.employeeNo} onChange={(e) => onChange("employeeNo", e.target.value)} className={getFieldInputClass(Boolean(fieldErrors?.employeeNo))} />
        {fieldErrors?.employeeNo ? <p className="text-xs text-rose-500">{fieldErrors.employeeNo}</p> : null}
        {!fieldErrors?.employeeNo && !isEdit && salesDuplicateMessage ? <p className="text-xs text-rose-500">{salesDuplicateMessage}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">代表处 / 办事处<RequiredMark /></span>
        <AdaptiveSelect
          value={form.officeName || ""}
          placeholder="请选择"
          sheetTitle="代表处 / 办事处"
          searchable
          searchPlaceholder="搜索代表处 / 办事处"
          options={[
            { value: "", label: "请选择" },
            ...officeOptions.map((option) => ({
              value: option.value ?? "",
              label: option.label || "无",
            })),
          ]}
          className={cn(
            fieldErrors?.officeName ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => onChange("officeName", value || undefined)}
        />
        {fieldErrors?.officeName ? <p className="text-xs text-rose-500">{fieldErrors.officeName}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">姓名<RequiredMark /></span>
        <input value={form.candidateName} onChange={(e) => onChange("candidateName", e.target.value)} className={getFieldInputClass(Boolean(fieldErrors?.candidateName))} />
        {fieldErrors?.candidateName ? <p className="text-xs text-rose-500">{fieldErrors.candidateName}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">联系方式<RequiredMark /></span>
        <input value={form.mobile} onChange={(e) => onChange("mobile", e.target.value)} className={getFieldInputClass(Boolean(fieldErrors?.mobile))} />
        {fieldErrors?.mobile ? <p className="text-xs text-rose-500">{fieldErrors.mobile}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">所属部门<RequiredMark /></span>
        <input
          value={form.targetDept || ""}
          onChange={(e) => onChange("targetDept", e.target.value)}
          placeholder="办事处/地市"
          className={getFieldInputClass(Boolean(fieldErrors?.targetDept))}
        />
        {fieldErrors?.targetDept ? <p className="text-xs text-rose-500">{fieldErrors.targetDept}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">所属行业<RequiredMark /></span>
        <AdaptiveSelect
          value={form.industry || ""}
          placeholder="请选择"
          sheetTitle="所属行业"
          options={[
            { value: "", label: "请选择" },
            ...industryOptions.map((option) => ({
              value: option.value ?? "",
              label: option.label || "无",
            })),
          ]}
          className={cn(
            fieldErrors?.industry ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => onChange("industry", value || undefined)}
        />
        {fieldErrors?.industry ? <p className="text-xs text-rose-500">{fieldErrors.industry}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">职务<RequiredMark /></span>
        <input value={form.title} onChange={(e) => onChange("title", e.target.value)} className={getFieldInputClass(Boolean(fieldErrors?.title))} />
        {fieldErrors?.title ? <p className="text-xs text-rose-500">{fieldErrors.title}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">合作意向<RequiredMark /></span>
        <AdaptiveSelect
          value={form.intentLevel}
          sheetTitle="合作意向"
          options={[
            { value: "high", label: "高" },
            { value: "medium", label: "中" },
            { value: "low", label: "低" },
          ]}
          className={cn(
            fieldErrors?.intentLevel ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => onChange("intentLevel", value)}
        />
        {fieldErrors?.intentLevel ? <p className="text-xs text-rose-500">{fieldErrors.intentLevel}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">销售是否在职<RequiredMark /></span>
        <AdaptiveSelect
          value={form.employmentStatus}
          sheetTitle="销售是否在职"
          options={[
            { value: "active", label: "是" },
            { value: "left", label: "否" },
          ]}
          className={cn(
            fieldErrors?.employmentStatus ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => onChange("employmentStatus", value)}
        />
        {fieldErrors?.employmentStatus ? <p className="text-xs text-rose-500">{fieldErrors.employmentStatus}</p> : null}
      </label>
      <label className="flex items-center justify-between rounded-xl border border-slate-200 px-4 py-3 dark:border-slate-800">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">销售以前是否做过云桌面项目</span>
        <input type="checkbox" checked={Boolean(form.hasDesktopExp)} onChange={(e) => onChange("hasDesktopExp", e.target.checked)} />
      </label>
      <label className="space-y-2 sm:col-span-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">跟进的云桌面项目</span>
        <div className="rounded-xl border border-dashed border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500 dark:border-slate-800 dark:bg-slate-900/30 dark:text-slate-400">
          首次新增不需要填写，关联商机后会自动按列表展示项目编码、项目名称和项目金额。
        </div>
      </label>
    </div>
  );

  const renderChannelForm = (
    form: CreateChannelExpansionPayload,
    onChange: <K extends keyof CreateChannelExpansionPayload>(key: K, value: CreateChannelExpansionPayload[K]) => void,
    isEdit = false,
    fieldErrors?: Partial<Record<ChannelField, string>>,
    invalidContactRows: number[] = [],
  ) => {
    const cityOptions = isEdit ? editCityOptions : createCityOptions;
    const cityDisabled = !form.province?.trim();

    return (
    <div className="crm-form-grid">
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">编码</span>
        <input
          value={form.channelCode || (isEdit ? "" : nextChannelCode || "系统自动生成")}
          readOnly
          className="crm-input-box-readonly crm-input-text w-full border border-slate-200 bg-slate-50 text-slate-500 outline-none dark:border-slate-800 dark:bg-slate-900/30 dark:text-slate-400"
        />
      </label>
      <label className="space-y-2 sm:col-span-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">渠道名称<RequiredMark /></span>
        <input value={form.channelName} onChange={(e) => onChange("channelName", e.target.value)} className={getFieldInputClass(Boolean(fieldErrors?.channelName))} />
        {fieldErrors?.channelName ? <p className="text-xs text-rose-500">{fieldErrors.channelName}</p> : null}
        {!fieldErrors?.channelName && !isEdit && channelDuplicateMessage ? <p className="text-xs text-rose-500">{channelDuplicateMessage}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">省份<RequiredMark /></span>
        <AdaptiveSelect
          value={form.province || ""}
          placeholder="请选择"
          sheetTitle="省份"
          searchable
          searchPlaceholder="搜索省份"
          options={[
            { value: "", label: "请选择" },
            ...provinceOptions.map((option) => ({
              value: option.value ?? "",
              label: option.label || "无",
            })),
          ]}
          className={cn(
            fieldErrors?.province ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => {
            const nextProvince = value || undefined;
            onChange("province", nextProvince);
            onChange("city", undefined);
            void loadCityOptions(nextProvince, isEdit);
          }}
        />
        {fieldErrors?.province ? <p className="text-xs text-rose-500">{fieldErrors.province}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">市<RequiredMark /></span>
        <AdaptiveSelect
          value={form.city || ""}
          placeholder={cityDisabled ? "请先选择省份" : "请选择"}
          sheetTitle="市"
          searchable
          searchPlaceholder="搜索市"
          disabled={cityDisabled}
          options={[
            { value: "", label: "请选择" },
            ...cityOptions.map((option) => ({
              value: option.value ?? "",
              label: option.label || "无",
            })),
          ]}
          className={cn(
            fieldErrors?.city ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => onChange("city", value || undefined)}
        />
        {fieldErrors?.city ? <p className="text-xs text-rose-500">{fieldErrors.city}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">办公地址<RequiredMark /></span>
        <input value={form.officeAddress || ""} onChange={(e) => onChange("officeAddress", e.target.value)} className={getFieldInputClass(Boolean(fieldErrors?.officeAddress))} />
        {fieldErrors?.officeAddress ? <p className="text-xs text-rose-500">{fieldErrors.officeAddress}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">聚焦行业<RequiredMark /></span>
        <AdaptiveSelect
          multiple
          value={form.channelIndustry || []}
          placeholder="请选择"
          sheetTitle="聚焦行业"
          options={industryOptions.map((option) => ({
            value: option.value ?? "",
            label: option.label || "无",
          }))}
          className={cn(
            fieldErrors?.channelIndustry ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => onChange("channelIndustry", value)}
        />
        {fieldErrors?.channelIndustry ? <p className="text-xs text-rose-500">{fieldErrors.channelIndustry}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">认证级别<RequiredMark /></span>
        <AdaptiveSelect
          value={form.certificationLevel || ""}
          placeholder="请选择"
          sheetTitle="认证级别"
          options={[
            { value: "", label: "请选择" },
            ...certificationLevelOptions.map((option) => ({
              value: option.value ?? "",
              label: option.label || "无",
            })),
          ]}
          className={cn(
            fieldErrors?.certificationLevel ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => onChange("certificationLevel", value || undefined)}
        />
        {fieldErrors?.certificationLevel ? <p className="text-xs text-rose-500">{fieldErrors.certificationLevel}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">年营收<RequiredMark /></span>
        <input type="number" value={form.annualRevenue ?? ""} onChange={(e) => onChange("annualRevenue", e.target.value ? Number(e.target.value) : undefined)} className={getFieldInputClass(Boolean(fieldErrors?.annualRevenue))} />
        {fieldErrors?.annualRevenue ? <p className="text-xs text-rose-500">{fieldErrors.annualRevenue}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">人员规模<RequiredMark /></span>
        <input type="number" value={form.staffSize ?? ""} onChange={(e) => onChange("staffSize", e.target.value ? Number(e.target.value) : undefined)} className={getFieldInputClass(Boolean(fieldErrors?.staffSize))} />
        {fieldErrors?.staffSize ? <p className="text-xs text-rose-500">{fieldErrors.staffSize}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">建立联系时间<RequiredMark /></span>
        <input type="date" value={form.contactEstablishedDate || ""} onChange={(e) => onChange("contactEstablishedDate", e.target.value)} className={getFieldInputClass(Boolean(fieldErrors?.contactEstablishedDate))} />
        {fieldErrors?.contactEstablishedDate ? <p className="text-xs text-rose-500">{fieldErrors.contactEstablishedDate}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">合作意向<RequiredMark /></span>
        <AdaptiveSelect
          value={form.intentLevel || "medium"}
          sheetTitle="合作意向"
          options={[
            { value: "high", label: "高" },
            { value: "medium", label: "中" },
            { value: "low", label: "低" },
          ]}
          className={cn(
            fieldErrors?.intentLevel ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => onChange("intentLevel", value)}
        />
        {fieldErrors?.intentLevel ? <p className="text-xs text-rose-500">{fieldErrors.intentLevel}</p> : null}
      </label>
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">渠道属性<RequiredMark /></span>
        <AdaptiveSelect
          multiple
          value={form.channelAttribute || []}
          placeholder="请选择"
          sheetTitle="渠道属性"
          options={channelAttributeOptions.map((option) => ({
            value: option.value ?? "",
            label: option.label || "无",
          }))}
          className={cn(
            fieldErrors?.channelAttribute ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => {
            onChange("channelAttribute", value);
            if (!channelOtherOptionValue || !value.includes(channelOtherOptionValue)) {
              onChange("channelAttributeCustom", "");
            }
          }}
        />
        {fieldErrors?.channelAttribute ? <p className="text-xs text-rose-500">{fieldErrors.channelAttribute}</p> : null}
      </label>
      {channelOtherOptionValue && (form.channelAttribute ?? []).includes(channelOtherOptionValue) ? (
        <label className="space-y-2">
          <span className="text-sm font-medium text-slate-700 dark:text-slate-300">其它渠道属性<RequiredMark /></span>
          <input
            value={form.channelAttributeCustom || ""}
            onChange={(e) => onChange("channelAttributeCustom", e.target.value)}
            placeholder="请输入具体渠道属性"
            className={getFieldInputClass(Boolean(fieldErrors?.channelAttributeCustom))}
          />
          {fieldErrors?.channelAttributeCustom ? <p className="text-xs text-rose-500">{fieldErrors.channelAttributeCustom}</p> : null}
        </label>
      ) : null}
      <label className="space-y-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">新华三内部属性<RequiredMark /></span>
        <AdaptiveSelect
          multiple
          value={form.internalAttribute || []}
          placeholder="请选择"
          sheetTitle="新华三内部属性"
          options={internalAttributeOptions.map((option) => ({
            value: option.value ?? "",
            label: option.label || "无",
          }))}
          className={cn(
            fieldErrors?.internalAttribute ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "",
          )}
          onChange={(value) => onChange("internalAttribute", value)}
        />
        {fieldErrors?.internalAttribute ? <p className="text-xs text-rose-500">{fieldErrors.internalAttribute}</p> : null}
      </label>
      <label className="flex items-center justify-between rounded-xl border border-slate-200 px-4 py-3 dark:border-slate-800">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">以前是否做过云桌面项目</span>
        <input type="checkbox" checked={Boolean(form.hasDesktopExp)} onChange={(e) => onChange("hasDesktopExp", e.target.checked)} />
      </label>
      <div className="crm-form-section sm:col-span-2">
        <div className="crm-form-section-header">
          <span className="text-sm font-semibold text-slate-800 dark:text-slate-200">人员信息<RequiredMark /></span>
          <button type="button" onClick={() => addChannelContact(isEdit)} className="rounded-lg bg-white px-3 py-1.5 text-xs font-medium text-violet-600 shadow-sm dark:bg-slate-800 dark:text-violet-400">
            添加人员
          </button>
        </div>
        <div className="crm-section-stack">
          {(form.contacts ?? []).map((contact, index) => (
            <div key={`${isEdit ? "edit" : "create"}-${index}`} className="grid grid-cols-1 gap-3 rounded-xl border border-slate-200 bg-white p-3 sm:grid-cols-[1fr_1fr_1fr_auto] dark:border-slate-700 dark:bg-slate-900/50">
              <input value={contact.name || ""} onChange={(e) => handleChannelContactChange(index, "name", e.target.value, isEdit)} placeholder="人员姓名" className={cn("w-full rounded-lg border bg-white px-3 py-2 text-sm outline-none focus:border-violet-500 focus:ring-1 focus:ring-violet-500 dark:bg-slate-900/50", invalidContactRows.includes(index) ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "border-slate-200 dark:border-slate-800")} />
              <input value={contact.mobile || ""} onChange={(e) => handleChannelContactChange(index, "mobile", e.target.value, isEdit)} placeholder="联系电话" className={cn("w-full rounded-lg border bg-white px-3 py-2 text-sm outline-none focus:border-violet-500 focus:ring-1 focus:ring-violet-500 dark:bg-slate-900/50", invalidContactRows.includes(index) ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "border-slate-200 dark:border-slate-800")} />
              <input value={contact.title || ""} onChange={(e) => handleChannelContactChange(index, "title", e.target.value, isEdit)} placeholder="职位" className={cn("w-full rounded-lg border bg-white px-3 py-2 text-sm outline-none focus:border-violet-500 focus:ring-1 focus:ring-violet-500 dark:bg-slate-900/50", invalidContactRows.includes(index) ? "border-rose-400 bg-rose-50/60 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/70 dark:bg-rose-500/10" : "border-slate-200 dark:border-slate-800")} />
              <button type="button" onClick={() => removeChannelContact(index, isEdit)} className="crm-btn-danger rounded-lg px-3 py-2 text-sm font-medium">
                删除
              </button>
            </div>
          ))}
        </div>
        {fieldErrors?.contacts ? <p className="text-xs text-rose-500">{fieldErrors.contacts}</p> : null}
      </div>
      <label className="space-y-2 sm:col-span-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">跟进的云桌面项目</span>
        <div className="rounded-xl border border-dashed border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500 dark:border-slate-800 dark:bg-slate-900/30 dark:text-slate-400">
          通过商机里的“关联渠道”自动带入项目编码、项目名称和项目金额。
        </div>
      </label>
      <label className="space-y-2 sm:col-span-2">
        <span className="text-sm font-medium text-slate-700 dark:text-slate-300">备注说明</span>
        <textarea rows={4} value={form.remark} onChange={(e) => onChange("remark", e.target.value)} className="crm-input-box crm-input-text w-full border border-slate-200 bg-white outline-none focus:border-violet-500 focus:ring-1 focus:ring-violet-500 dark:border-slate-800 dark:bg-slate-900/50" />
      </label>
    </div>
  );
  };

  return (
    <div className="crm-page-stack">
      <header className="crm-page-header">
        <div className="crm-page-heading">
          <h1 className="crm-page-title">拓展管理</h1>
        </div>
        <div className="flex items-center gap-2">
          <button
            onClick={handleExport}
            disabled={exporting}
            className={cn("crm-btn-sm crm-btn-secondary flex items-center gap-2 disabled:cursor-not-allowed disabled:opacity-60", disableMobileMotion ? "active:scale-100" : "active:scale-95")}
          >
            <Download className="crm-icon-md" />
            <span className="hidden sm:inline">{exporting ? "导出中..." : "导出"}</span>
          </button>
          <button
            onClick={handleOpenCreate}
            className={cn("crm-btn-sm crm-btn-primary flex items-center gap-2", disableMobileMotion ? "active:scale-100" : "active:scale-95")}
          >
            <Plus className="crm-icon-md" />
            <span className="hidden sm:inline">新增</span>
          </button>
        </div>
      </header>

      <div className={cn("crm-filter-bar flex", !disableMobileMotion && "backdrop-blur-sm")}>
        <button
          onClick={() => handleTabChange("sales")}
          className={`flex-1 rounded-lg py-2 text-sm font-medium transition-colors duration-200 ${
            activeTab === "sales" ? "bg-white text-violet-600 shadow-sm dark:bg-slate-800 dark:text-violet-400" : "text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-white"
          }`}
        >
          销售人员拓展
        </button>
        <button
          onClick={() => handleTabChange("channel")}
          className={`flex-1 rounded-lg py-2 text-sm font-medium transition-colors duration-200 ${
            activeTab === "channel" ? "bg-white text-violet-600 shadow-sm dark:bg-slate-800 dark:text-violet-400" : "text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-white"
          }`}
        >
          渠道拓展
        </button>
      </div>

      <div className="group relative">
        <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400 transition-colors group-focus-within:text-violet-500" />
        <input
          type="text"
          placeholder="搜索工号、姓名、渠道名称、行业..."
          value={keyword}
          onChange={(event) => {
            setKeyword(event.target.value);
            setExportError("");
          }}
          className="crm-input-box crm-input-text w-full border border-slate-200 bg-white pl-10 text-slate-900 outline-none transition-all focus:border-violet-500 focus:ring-1 focus:ring-violet-500 dark:border-slate-800 dark:bg-slate-900/50 dark:text-white"
        />
      </div>

      {exportError ? <div className="crm-alert crm-alert-error">{exportError}</div> : null}

      <div className="crm-list-stack">
        {activeTab === "sales" ? (
          salesData.length > 0 ? (
            salesData.map((item, i) => {
              const isOwnedByCurrentUser = currentUserId !== undefined && item.ownerUserId === currentUserId;
              return (
                <motion.div
                  initial={disableMobileMotion ? false : { opacity: 0, y: 10 }}
                  animate={{ opacity: 1, y: 0 }}
                  transition={disableMobileMotion ? { duration: 0 } : { delay: i * 0.05 }}
                  key={item.id}
                  onClick={() => setSelectedItem(item)}
                  className={cn(
                    "crm-card crm-card-pad relative rounded-2xl transition-shadow transition-colors",
                    isOwnedByCurrentUser
                      ? "cursor-pointer hover:border-violet-100 hover:shadow-md dark:hover:border-violet-900/50"
                      : "cursor-pointer border-slate-100 bg-slate-50/45 hover:border-slate-200 hover:shadow-sm dark:border-slate-800/80 dark:bg-slate-900/35 dark:hover:border-slate-700",
                  )}
                >
                  {isOwnedByCurrentUser ? (
                    <div className="pointer-events-none absolute inset-x-5 top-0 h-1.5 rounded-b-full bg-gradient-to-r from-violet-400/85 via-fuchsia-400/70 to-indigo-400/85 shadow-[0_6px_16px_rgba(124,58,237,0.18)] dark:from-violet-400/70 dark:via-fuchsia-400/55 dark:to-indigo-400/70" />
                  ) : null}
                  <div className="flex items-start gap-3">
                    <div className="min-w-0 flex-1">
                      <h3 className="break-anywhere text-base font-semibold text-slate-900 dark:text-white sm:text-lg">{item.name || "无"}</h3>
                      <p className="break-anywhere mt-1 text-xs leading-5 text-slate-500 dark:text-slate-400 sm:text-sm">{item.officeName || "无"} · {item.dept || "无"} · {item.title || "无"}</p>
                      <div className="mt-2 flex flex-wrap items-center gap-2">
                        <span
                          className={cn(
                            "rounded-full border px-2.5 py-1 text-[11px] font-semibold leading-none",
                            isOwnedByCurrentUser
                              ? "border-emerald-200 bg-emerald-50 text-emerald-600 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300"
                              : "border-slate-200 bg-slate-50 text-slate-500 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-300",
                          )}
                        >
                          {isOwnedByCurrentUser ? "我的" : "只读"}
                        </span>
                        <span className={`crm-pill shrink-0 ${item.active ? "crm-pill-emerald" : "crm-pill-neutral"}`}>
                          {item.active ? "在职" : "离职"}
                        </span>
                      </div>
                    </div>
                  </div>
              <div className="mt-4 grid grid-cols-1 gap-y-3 text-xs sm:grid-cols-2 sm:text-sm">
                <div className="flex items-center gap-2 text-slate-600 dark:text-slate-300">
                  <span className="text-slate-400 dark:text-slate-500">意向:</span>
                  <span className={item.intent === "高" ? "font-medium text-rose-600 dark:text-rose-400" : ""}>{item.intent || "无"}</span>
                </div>
                <div className="flex items-center gap-2 text-slate-600 dark:text-slate-300">
                  <span className="text-slate-400 dark:text-slate-500">跟进项目金额:</span>
                  {formatRelatedProjectAmount(item.relatedProjects)}
                </div>
                <div className="flex items-center gap-2 text-slate-600 dark:text-slate-300">
                  <span className="text-slate-400 dark:text-slate-500">创建人:</span>
                  <span className="font-medium text-slate-900 dark:text-white">{item.owner || "无"}</span>
                </div>
              </div>
                </motion.div>
              );
            })
          ) : renderEmpty()
        ) : channelData.length > 0 ? (
          channelData.map((item, i) => {
            const isOwnedByCurrentUser = currentUserId !== undefined && item.ownerUserId === currentUserId;
            return (
              <motion.div
                initial={disableMobileMotion ? false : { opacity: 0, y: 10 }}
                animate={{ opacity: 1, y: 0 }}
                transition={disableMobileMotion ? { duration: 0 } : { delay: i * 0.05 }}
                key={item.id}
                onClick={() => setSelectedItem(item)}
                className={cn(
                  "crm-card crm-card-pad relative rounded-2xl transition-shadow transition-colors",
                  isOwnedByCurrentUser
                    ? "cursor-pointer hover:border-violet-100 hover:shadow-md dark:hover:border-violet-900/50"
                    : "cursor-pointer border-slate-100 bg-slate-50/45 hover:border-slate-200 hover:shadow-sm dark:border-slate-800/80 dark:bg-slate-900/35 dark:hover:border-slate-700",
                )}
              >
                {isOwnedByCurrentUser ? (
                  <div className="pointer-events-none absolute inset-x-5 top-0 h-1.5 rounded-b-full bg-gradient-to-r from-violet-400/85 via-fuchsia-400/70 to-indigo-400/85 shadow-[0_6px_16px_rgba(124,58,237,0.18)] dark:from-violet-400/70 dark:via-fuchsia-400/55 dark:to-indigo-400/70" />
                ) : null}
                <div className="flex items-start gap-3">
                  <div className="min-w-0 flex-1">
                    <h3 className="break-anywhere text-base font-semibold text-slate-900 dark:text-white sm:text-lg">{item.name || "无"}</h3>
                    <p className="break-anywhere mt-1 text-xs leading-5 text-slate-500 dark:text-slate-400 sm:text-sm">
                      {item.province || "无"} · {item.city || "无"} · {item.certificationLevel || "无"}
                    </p>
                    <div className="mt-2 flex flex-wrap items-center gap-2">
                      <span
                        className={cn(
                          "rounded-full border px-2.5 py-1 text-[11px] font-semibold leading-none",
                          isOwnedByCurrentUser
                            ? "border-emerald-200 bg-emerald-50 text-emerald-600 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300"
                            : "border-slate-200 bg-slate-50 text-slate-500 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-300",
                        )}
                      >
                        {isOwnedByCurrentUser ? "我的" : "只读"}
                      </span>
                      <span className={`crm-pill shrink-0 ${item.intent === "高" ? "crm-pill-rose" : item.intent === "中" ? "crm-pill-amber" : "crm-pill-neutral"}`}>
                        {item.intent ? `${item.intent}意向` : "未评估"}
                      </span>
                    </div>
                  </div>
                </div>
              <div className="mt-4 grid grid-cols-1 gap-y-3 text-xs sm:grid-cols-2 sm:text-sm">
                <div className="flex items-center gap-2 text-slate-600 dark:text-slate-300">
                  <span className="text-slate-400 dark:text-slate-500">建立联系:</span>
                  {item.establishedDate || "无"}
                </div>
                <div className="flex items-center gap-2 text-slate-600 dark:text-slate-300">
                  <span className="text-slate-400 dark:text-slate-500">跟进项目金额:</span>
                  {formatRelatedProjectAmount(item.relatedProjects)}
                </div>
                <div className="flex items-center gap-2 text-slate-600 dark:text-slate-300">
                  <span className="text-slate-400 dark:text-slate-500">创建人:</span>
                  <span className="font-medium text-slate-900 dark:text-white">{item.owner || "无"}</span>
                </div>
              </div>
              </motion.div>
            );
          })
        ) : renderEmpty()}
      </div>

      <AnimatePresence>
        {createOpen && (
          <ModalShell
            title={`新增${activeTab === "sales" ? "销售人员拓展" : "渠道拓展"}`}
            subtitle="支持电脑和手机填写，提交后自动刷新列表。"
            onClose={resetCreateState}
            footer={(
              <div className="flex flex-col-reverse gap-3 sm:flex-row sm:justify-end">
                <button onClick={resetCreateState} className="crm-btn crm-btn-secondary">取消</button>
                <button onClick={() => void handleCreateSubmit()} disabled={submitting} className="crm-btn crm-btn-primary disabled:cursor-not-allowed disabled:opacity-60">{submitting ? "提交中..." : "确认新增"}</button>
              </div>
            )}
          >
            {activeTab === "sales" ? renderSalesForm(salesForm, handleSalesChange, salesCreateFieldErrors, false) : renderChannelForm(channelForm, handleChannelChange, false, channelCreateFieldErrors, invalidCreateChannelContactRows)}
            {createError ? <div className="crm-alert crm-alert-error mt-4">{createError}</div> : null}
          </ModalShell>
        )}
      </AnimatePresence>

      <AnimatePresence>
        {editOpen && selectedItem && (
          <ModalShell
            title={`编辑${selectedItem.type === "sales" ? "销售人员拓展" : "渠道拓展"}`}
            subtitle="修改后会实时更新本人名下的拓展资料。"
            onClose={resetEditState}
            footer={(
              <div className="flex flex-col-reverse gap-3 sm:flex-row sm:justify-end">
                <button onClick={resetEditState} className="crm-btn crm-btn-secondary">取消</button>
                <button onClick={() => void handleEditSubmit()} disabled={submitting} className="crm-btn crm-btn-primary disabled:cursor-not-allowed disabled:opacity-60">{submitting ? "保存中..." : "保存修改"}</button>
              </div>
            )}
          >
            {selectedItem.type === "sales" ? renderSalesForm(editSalesForm, handleEditSalesChange, salesEditFieldErrors, true) : renderChannelForm(editChannelForm, handleEditChannelChange, true, channelEditFieldErrors, invalidEditChannelContactRows)}
            {editError ? <div className="crm-alert crm-alert-error mt-4">{editError}</div> : null}
          </ModalShell>
        )}
      </AnimatePresence>

      <AnimatePresence>
        {selectedItem && (
          <>
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              onClick={() => setSelectedItem(null)}
              className={`fixed inset-0 z-40 bg-slate-900/20 backdrop-blur-sm transition-opacity dark:bg-slate-900/60 ${
                hasForegroundModal ? "pointer-events-none opacity-30" : ""
              }`}
            />
            <motion.div
              initial={{ x: "100%", y: 0 }}
              animate={{ x: 0, y: 0 }}
              exit={{ x: "100%", y: 0 }}
              transition={{ type: "spring", damping: 25, stiffness: 200 }}
              className={`fixed inset-x-0 bottom-0 z-50 flex h-[88dvh] w-full flex-col rounded-t-3xl border border-slate-200 bg-white shadow-2xl transition-opacity dark:border-slate-800 dark:bg-slate-900 sm:inset-y-0 sm:right-0 sm:left-auto sm:h-full sm:max-w-2xl lg:max-w-3xl sm:rounded-none sm:rounded-l-3xl sm:border-l ${
                hasForegroundModal ? "pointer-events-none opacity-20" : ""
              }`}
            >
              <div className="flex items-center justify-between border-b border-slate-100 px-5 py-4 dark:border-slate-800 sm:px-6">
                <div className="flex items-center gap-3">
                  <div className="h-1.5 w-10 rounded-full bg-slate-200 sm:hidden dark:bg-slate-700" />
                  <h2 className="text-base font-semibold text-slate-900 dark:text-white sm:text-lg">{selectedItem.type === "sales" ? "销售拓展详情" : "渠道拓展详情"}</h2>
                </div>
                  <button onClick={() => setSelectedItem(null)} className="rounded-full p-2 text-slate-400 transition-colors hover:bg-slate-100 dark:hover:bg-slate-800">
                    <X className="crm-icon-lg" />
                </button>
              </div>

              <div className="flex-1 overflow-y-auto px-5 py-5 sm:px-6">
                <div className="crm-modal-stack">
                <div>
                  {selectedItem.type === "sales" ? (
                    <p className="text-xs font-medium uppercase tracking-[0.18em] text-slate-400 dark:text-slate-500">工号 {selectedItem.employeeNo || "无"}</p>
                  ) : (
                    <p className="text-xs font-medium uppercase tracking-[0.18em] text-slate-400 dark:text-slate-500">{selectedItem.channelCode || "未编码"}</p>
                  )}
                  <h3 className="break-anywhere text-lg font-bold text-slate-900 dark:text-white sm:text-xl">{selectedItem.name || "无"}</h3>
                  <p className="break-anywhere mt-1 text-xs leading-5 text-slate-500 dark:text-slate-400 sm:text-sm">
                    {selectedItem.type === "sales"
                      ? `${selectedItem.officeName || "无"} · ${selectedItem.dept || "无"} · ${selectedItem.title || "无"}`
                      : `${selectedItem.province || "无"} · ${selectedItem.city || "无"} · ${selectedItem.channelIndustry || "无"} · ${selectedItem.certificationLevel || "无"}`}
                  </p>
                  <div className="mt-3 flex flex-wrap gap-2">
                    {selectedItem.type === "sales" ? (
                      <span className={`crm-pill ${selectedItem.active ? "crm-pill-emerald" : "crm-pill-neutral"}`}>
                        {selectedItem.active ? "在职" : "离职"}
                      </span>
                    ) : null}
                  </div>
                </div>

                <div className="crm-section-stack">
                  <h4 className="flex items-center gap-2 text-sm font-semibold text-slate-900 dark:text-white">
                    <FileText className="crm-icon-md text-violet-500" />
                    基本信息
                  </h4>
                  <div className="crm-detail-grid text-sm sm:grid-cols-2">
                    {selectedItem.type === "sales" ? (
                      <>
                        <DetailItem label="工号" value={selectedItem.employeeNo || "无"} />
                        <DetailItem label="代表处 / 办事处" value={selectedItem.officeName || "无"} />
                        <DetailItem label="联系方式" value={selectedItem.phone || "无"} icon={<Phone className="h-3 w-3" />} />
                        <DetailItem label="所属部门" value={selectedItem.dept || "无"} />
                        <DetailItem label="所属行业" value={selectedItem.industry || "无"} icon={<Building2 className="h-3 w-3" />} />
                        <DetailItem label="职务" value={selectedItem.title || "无"} />
                        <DetailItem label="合作意向" value={selectedItem.intent || "无"} />
                        <DetailItem label="销售以前是否做过云桌面项目" value={selectedItem.hasExp ? "是" : "否"} />
                        <DetailItem label="销售是否在职" value={selectedItem.active ? "是" : "否"} />
                      </>
                    ) : (
                      <>
                        <DetailItem label="编码" value={selectedItem.channelCode || "无"} />
                        <DetailItem label="省份" value={selectedItem.province || "无"} />
                        <DetailItem label="市" value={selectedItem.city || "无"} />
                        <DetailItem label="认证级别" value={selectedItem.certificationLevel || "无"} />
                        <DetailItem label="办公地址" value={selectedItem.officeAddress || "无"} className="sm:col-span-2" />
                        <DetailItem label="聚焦行业" value={selectedItem.channelIndustry || "无"} icon={<Building2 className="h-3 w-3" />} />
                        <DetailItem label="营收规模" value={selectedItem.revenue || "无"} />
                        <DetailItem label="人员规模" value={`${selectedItem.size ?? 0}人`} />
                        <DetailItem label="建立联系时间" value={selectedItem.establishedDate || "无"} icon={<Calendar className="h-3 w-3" />} />
                        <DetailItem label="合作意向" value={selectedItem.intent || "无"} />
                        <DetailItem label="以前是否做过云桌面项目" value={selectedItem.hasDesktopExp ? "是" : "否"} />
                        <DetailItem label="渠道属性" value={selectedItem.channelAttribute || "无"} />
                        <DetailItem label="新华三内部属性" value={selectedItem.internalAttribute || "无"} />
                      </>
                    )}
                    {selectedItem.type !== "sales" ? <DetailItem label="备注说明" value={selectedItem.notes || "无"} className="sm:col-span-2" /> : null}
                  </div>
                </div>

                {selectedItem.type === "sales" ? (
                  <div className="crm-section-stack">
                    <div className="flex rounded-2xl border border-slate-200 bg-slate-50 p-1 dark:border-slate-800 dark:bg-slate-800/40">
                      <button
                        type="button"
                        onClick={() => setSalesDetailTab("projects")}
                        className={`flex-1 rounded-xl px-4 py-2 text-sm font-medium transition-colors ${
                          salesDetailTab === "projects"
                            ? "bg-white text-violet-600 shadow-sm dark:bg-slate-900 dark:text-violet-400"
                            : "text-slate-500 dark:text-slate-400"
                        }`}
                      >
                        跟进项目
                      </button>
                      <button
                        type="button"
                        onClick={() => setSalesDetailTab("followups")}
                        className={`flex-1 rounded-xl px-4 py-2 text-sm font-medium transition-colors ${
                          salesDetailTab === "followups"
                            ? "bg-white text-violet-600 shadow-sm dark:bg-slate-900 dark:text-violet-400"
                            : "text-slate-500 dark:text-slate-400"
                        }`}
                      >
                        跟进记录
                      </button>
                    </div>

                    {salesDetailTab === "projects" ? (
                      <div className="crm-section-stack">
                        {(selectedItem.relatedProjects?.length ?? 0) > 0 ? (
                          <div className="crm-list-stack">
                            {selectedItem.relatedProjects?.map((project) => (
                              <div
                                key={project.opportunityId}
                                className="crm-detail-grid text-sm sm:grid-cols-3"
                              >
                                <DetailItem label="项目编码" value={project.opportunityCode || "无"} />
                                <DetailItem label="项目名称" value={project.opportunityName || "未命名项目"} />
                                <DetailItem label="项目金额" value={`¥${new Intl.NumberFormat("zh-CN").format(Number(project.amount || 0))}`} />
                              </div>
                            ))}
                          </div>
                        ) : (
                          <div className="crm-empty-panel">
                            暂无关联项目
                          </div>
                        )}
                      </div>
                    ) : (
                      <div className="crm-section-stack">
                        <h4 className="flex items-center gap-2 text-sm font-semibold text-slate-900 dark:text-white">
                          <Clock className="crm-icon-md text-violet-500" />
                          跟进记录
                        </h4>
                        {renderFollowUpTimeline()}
                      </div>
                    )}
                  </div>
                ) : (
                  <div className="crm-section-stack">
                    <div className="flex rounded-2xl border border-slate-200 bg-slate-50 p-1 dark:border-slate-800 dark:bg-slate-800/40">
                      <button
                        type="button"
                        onClick={() => setChannelDetailTab("projects")}
                        className={`flex-1 rounded-xl px-3 py-2 text-sm font-medium transition-colors ${
                          channelDetailTab === "projects"
                            ? "bg-white text-violet-600 shadow-sm dark:bg-slate-900 dark:text-violet-400"
                            : "text-slate-500 dark:text-slate-400"
                        }`}
                      >
                        跟进项目
                      </button>
                      <button
                        type="button"
                        onClick={() => setChannelDetailTab("contacts")}
                        className={`flex-1 rounded-xl px-3 py-2 text-sm font-medium transition-colors ${
                          channelDetailTab === "contacts"
                            ? "bg-white text-violet-600 shadow-sm dark:bg-slate-900 dark:text-violet-400"
                            : "text-slate-500 dark:text-slate-400"
                        }`}
                      >
                        人员信息
                      </button>
                      <button
                        type="button"
                        onClick={() => setChannelDetailTab("followups")}
                        className={`flex-1 rounded-xl px-3 py-2 text-sm font-medium transition-colors ${
                          channelDetailTab === "followups"
                            ? "bg-white text-violet-600 shadow-sm dark:bg-slate-900 dark:text-violet-400"
                            : "text-slate-500 dark:text-slate-400"
                        }`}
                      >
                        跟进记录
                      </button>
                    </div>

                    {channelDetailTab === "projects" ? (
                      (selectedItem.relatedProjects?.length ?? 0) > 0 ? (
                        <div className="crm-list-stack">
                          {selectedItem.relatedProjects?.map((project) => (
                            <div
                              key={project.opportunityId}
                              className="crm-detail-grid text-sm sm:grid-cols-3"
                            >
                              <DetailItem label="项目编码" value={project.opportunityCode || "无"} />
                              <DetailItem label="项目名称" value={project.opportunityName || "未命名项目"} />
                              <DetailItem label="项目金额" value={`¥${new Intl.NumberFormat("zh-CN").format(Number(project.amount || 0))}`} />
                            </div>
                          ))}
                        </div>
                      ) : (
                        <div className="crm-empty-panel">
                          暂无关联项目
                        </div>
                      )
                    ) : null}

                    {channelDetailTab === "contacts" ? (
                      (selectedItem.contacts?.length ?? 0) > 0 ? (
                        <div className="space-y-3">
                          {selectedItem.contacts?.map((contact, index) => (
                            <div key={`${contact.name || "contact"}-${index}`} className="grid grid-cols-1 gap-3 rounded-xl border border-slate-100 bg-slate-50/50 p-4 text-sm dark:border-slate-800 dark:bg-slate-800/20 sm:grid-cols-3">
                              <div><p className="mb-1 text-slate-500 dark:text-slate-400">人员姓名</p><p className="break-anywhere font-medium text-slate-900 dark:text-white">{contact.name || "无"}</p></div>
                              <div><p className="mb-1 text-slate-500 dark:text-slate-400">联系电话</p><p className="break-anywhere font-medium text-slate-900 dark:text-white">{contact.mobile || "无"}</p></div>
                              <div><p className="mb-1 text-slate-500 dark:text-slate-400">职位</p><p className="break-anywhere font-medium text-slate-900 dark:text-white">{contact.title || "无"}</p></div>
                            </div>
                          ))}
                        </div>
                      ) : (
                        <div className="crm-empty-panel">
                          暂无人员信息
                        </div>
                      )
                    ) : null}

                    {channelDetailTab === "followups" ? (
                      renderFollowUpTimeline()
                    ) : null}
                  </div>
                )}
              </div>

              <div className="sticky bottom-0 bg-slate-50/95 px-4 pb-[calc(1rem+env(safe-area-inset-bottom))] pt-4 backdrop-blur sm:static sm:p-4 dark:bg-slate-900/90">
                {!canEditSelectedItem ? (
                  <p className="mb-3 text-xs text-slate-400 dark:text-slate-500">当前记录非本人创建，仅支持查看详情，不能编辑。</p>
                ) : null}
                <div className="flex">
                  <button
                    type="button"
                    onClick={() => void handleOpenEdit()}
                    disabled={!canEditSelectedItem}
                    title={canEditSelectedItem ? "编辑资料" : "仅本人可操作"}
                    className="crm-btn-sm crm-btn-secondary flex-1 disabled:cursor-not-allowed disabled:opacity-60"
                  >
                    {canEditSelectedItem ? "编辑资料" : "仅本人可操作"}
                  </button>
                </div>
              </div>
              </div>
            </motion.div>
          </>
        )}
      </AnimatePresence>
    </div>
  );
}

function formatAmount(value: number) {
  return `¥${new Intl.NumberFormat("zh-CN").format(value)}`;
}

function formatRelatedProjectAmount(projects?: Array<{ amount?: number }>) {
  if (!projects || projects.length === 0) {
    return "无";
  }
  const totalAmount = projects.reduce((sum, project) => sum + Number(project.amount || 0), 0);
  return formatAmount(totalAmount);
}

function getExpansionFollowUpSummary(record: {
  type?: string;
  date?: string;
  content?: string;
  visitStartTime?: string;
  evaluationContent?: string;
  nextPlan?: string;
}) {
  const content = record.content || "";
  const parsedVisit = extractFollowUpField(content, "拜访时间");
  const parsedEvaluation = extractFollowUpField(content, "沟通内容");
  const parsedPlan = extractFollowUpField(content, "后续规划");
  const fallbackVisitStartTime = record.type === "工作日报" && record.date
    ? record.date.slice(0, 10)
    : undefined;

  return {
    visitStartTime: normalizeFollowUpDisplayValue(formatFollowUpDateValue(
      pickFollowUpValue(record.visitStartTime, parsedVisit, fallbackVisitStartTime),
    )),
    evaluationContent: normalizeFollowUpDisplayValue(
      pickFollowUpValue(record.evaluationContent, parsedEvaluation),
    ),
    nextPlan: normalizeFollowUpDisplayValue(
      pickFollowUpValue(record.nextPlan, parsedPlan),
    ),
  };
}

function pickFollowUpValue(...values: Array<string | undefined>) {
  return values.find((value) => {
    const normalized = value?.trim();
    return normalized && normalized !== "无";
  });
}

function formatFollowUpDateValue(value?: string) {
  const normalized = value?.trim();
  if (!normalized) {
    return undefined;
  }
  const match = normalized.match(/^(\d{4}-\d{2}-\d{2})/);
  return match ? match[1] : normalized;
}

function extractFollowUpField(content: string, label: string) {
  const normalized = content.replace(/\r/g, "");
  const escapedLabel = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  const match = normalized.match(new RegExp(`${escapedLabel}：([^\\n]+)`));
  return match?.[1]?.trim();
}

function normalizeFollowUpDisplayValue(value?: string) {
  const normalized = value?.trim();
  return normalized ? normalized : "无";
}
