import {
  FLOCK_LIMITS,
  FLOCK_VALIDATION_MESSAGES,
  fitsFlockTrailerCargo,
} from "@/lib/constants/flock-limits";
import {
  dimValueToIn,
  normalizeDimUnit,
  normalizeWeightUnit,
  toAxelWholeInches,
  toAxelWholePounds,
  weightUnitAmbiguousMessage,
  weightValueToLb,
} from "@/modules/quote/unit-converter";
import {
  defaultFlockPickupDateIso,
  flockPickupDateValidationMessageFromDisplay,
  flockPickupDisplayFromIso,
} from "@/lib/flock/pickup-date";
import { ValidationError } from "@/modules/quote/types";
import type {
  FlockQuoteInput,
  FlockRegistrationOverride,
} from "@/workers/rpa/flock/types";

const DATE_RE = /^\d{2}\/\d{2}\/\d{4}$/;
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const SHIPMENTS_OPTIONS = new Set(["1-25", "26-50", "51-100", "101+"]);

function optionalTrim(value: unknown): string | undefined {
  if (typeof value !== "string") {
    return undefined;
  }
  const trimmed = value.trim();
  return trimmed || undefined;
}

function parseRegistrationBlock(
  raw: unknown,
): FlockRegistrationOverride | undefined {
  if (!raw || typeof raw !== "object") {
    return undefined;
  }
  const r = raw as Record<string, unknown>;
  const firstName = optionalTrim(r.first_name ?? r.firstName);
  const lastName = optionalTrim(r.last_name ?? r.lastName);
  const company = optionalTrim(r.company ?? r.company_name ?? r.companyName);
  const email = optionalTrim(r.email ?? r.work_email ?? r.workEmail);
  const phoneRaw = optionalTrim(r.phone ?? r.phone_number ?? r.phoneNumber);
  const shipmentsPerMonth = optionalTrim(
    r.shipments_per_month ?? r.shipmentsPerMonth,
  );

  if (
    !firstName &&
    !lastName &&
    !company &&
    !email &&
    !phoneRaw &&
    !shipmentsPerMonth
  ) {
    return undefined;
  }

  if (email && !EMAIL_RE.test(email)) {
    throw new ValidationError("请填写有效的工作邮箱");
  }

  let phone: string | undefined;
  if (phoneRaw) {
    const digits = phoneRaw.replace(/\D/g, "").slice(-10);
    if (digits.length !== 10) {
      throw new ValidationError("请填写有效的 10 位美国电话号码");
    }
    phone = digits;
  }

  if (shipmentsPerMonth && !SHIPMENTS_OPTIONS.has(shipmentsPerMonth)) {
    throw new ValidationError("月出货量选项无效");
  }

  return {
    firstName,
    lastName,
    company,
    email,
    phone,
    shipmentsPerMonth,
  };
}

function asObject(body: unknown): Record<string, unknown> {
  if (!body || typeof body !== "object") {
    throw new ValidationError("请求体格式无效");
  }
  return body as Record<string, unknown>;
}

function reqString(value: unknown, message: string): string {
  if (typeof value !== "string" || !value.trim()) {
    throw new ValidationError(message);
  }
  return value.trim();
}

function parsePositiveNumber(value: unknown, label: string): number {
  const n =
    typeof value === "number"
      ? value
      : typeof value === "string"
        ? Number(value.trim())
        : NaN;
  if (!Number.isFinite(n) || n <= 0) {
    throw new ValidationError(`请填写有效的${label}`);
  }
  return n;
}

function normalizeZip(raw: string, emptyMessage: string): string {
  const zip = raw.trim();
  if (!zip) {
    throw new ValidationError(emptyMessage);
  }
  if (!FLOCK_LIMITS.zipPattern.test(zip)) {
    throw new ValidationError(FLOCK_VALIDATION_MESSAGES.zipFormat);
  }
  return zip.slice(0, 5);
}

/** 默认取货日（下一工作日），供前端预填 */
export function defaultFlockPickupDate(): string {
  return flockPickupDisplayFromIso(defaultFlockPickupDateIso());
}

/**
 * 校验 Flock 询价入参；重量/尺寸支持 kg/cm，换算为 lb/in 后小数进一（ceil）
 * 例：500 kg → 1102.31 → 1103 lb
 */
export function validateFlockQuoteInput(
  body: unknown,
): FlockQuoteInput & { request_id: string; customer_id: string } {
  const o = asObject(body);
  const requestId = reqString(o.request_id, "请填写请求标识");
  const customerId = reqString(o.customer_id, "请填写客户标识");
  const rawInput = o.flock_input;
  if (!rawInput || typeof rawInput !== "object") {
    throw new ValidationError("请填写 Flock 表单参数");
  }
  const f = rawInput as Record<string, unknown>;

  const pickupDate = reqString(
    f.pickup_date ?? f.pickupDate,
    FLOCK_VALIDATION_MESSAGES.pickupDate,
  );
  if (!DATE_RE.test(pickupDate)) {
    throw new ValidationError("取货日期格式须为 MM/DD/YYYY");
  }
  const pickupDateError =
    flockPickupDateValidationMessageFromDisplay(pickupDate);
  if (pickupDateError) {
    throw new ValidationError(pickupDateError);
  }

  const pickupZip = normalizeZip(
    reqString(
      f.pickup_zip ?? f.pickupZip,
      FLOCK_VALIDATION_MESSAGES.pickupZip,
    ),
    FLOCK_VALIDATION_MESSAGES.pickupZip,
  );
  const deliveryZip = normalizeZip(
    reqString(
      f.delivery_zip ?? f.deliveryZip,
      FLOCK_VALIDATION_MESSAGES.deliveryZip,
    ),
    FLOCK_VALIDATION_MESSAGES.deliveryZip,
  );
  if (pickupZip === deliveryZip) {
    throw new ValidationError("提货与派送邮编不能相同");
  }

  const formModeRaw = f.form_mode ?? f.formMode;
  const formMode =
    formModeRaw === "logged_in_quick" ? ("logged_in_quick" as const) : undefined;

  const palletRaw = f.pallet_count ?? f.palletCount;
  const palletCount =
    typeof palletRaw === "number"
      ? palletRaw
      : Number(String(palletRaw ?? "").trim());
  const qtyMin = formMode === "logged_in_quick" ? 1 : FLOCK_LIMITS.palletCount.min;
  const qtyMax =
    formMode === "logged_in_quick" ? 999 : FLOCK_LIMITS.palletCount.max;
  if (
    !Number.isInteger(palletCount) ||
    palletCount < qtyMin ||
    palletCount > qtyMax
  ) {
    throw new ValidationError(
      formMode === "logged_in_quick"
        ? "货物数量须为 1–999 的整数"
        : FLOCK_VALIDATION_MESSAGES.palletCount,
    );
  }

  const weightObj =
    f.total_weight && typeof f.total_weight === "object"
      ? (f.total_weight as Record<string, unknown>)
      : null;
  const weightValue = parsePositiveNumber(
    weightObj?.value ?? f.total_weight_lb ?? f.totalWeightLb,
    "总运输重量",
  );
  const weightUnitRaw =
    weightObj && typeof weightObj.unit === "string"
      ? weightObj.unit
      : "lb";
  const weightAmbiguous = weightUnitAmbiguousMessage(weightUnitRaw);
  if (weightAmbiguous) {
    throw new ValidationError(weightAmbiguous);
  }
  const weightUnit = normalizeWeightUnit(weightUnitRaw);
  if (!weightUnit) {
    throw new ValidationError("重量单位须为 lb、kg 或 t/tonne（公制吨）");
  }
  const totalWeightLb = toAxelWholePounds(
    weightValueToLb(weightValue, weightUnit),
  );
  if (totalWeightLb > FLOCK_LIMITS.totalWeightLbMax) {
    throw new ValidationError(FLOCK_VALIDATION_MESSAGES.totalWeight);
  }

  const dimObj =
    f.dimensions && typeof f.dimensions === "object"
      ? (f.dimensions as Record<string, unknown>)
      : null;
  const dimUnitRaw =
    dimObj && typeof dimObj.unit === "string" ? dimObj.unit : "in";
  const dimUnit = normalizeDimUnit(dimUnitRaw);
  if (!dimUnit) {
    throw new ValidationError("尺寸单位须为 in、cm 或 m");
  }
  const lengthRaw = parsePositiveNumber(
    dimObj?.length ?? f.length_in ?? f.lengthIn ?? FLOCK_LIMITS.defaultDimsIn.length,
    "长度",
  );
  const widthRaw = parsePositiveNumber(
    dimObj?.width ?? f.width_in ?? f.widthIn ?? FLOCK_LIMITS.defaultDimsIn.width,
    "宽度",
  );
  const heightRaw = parsePositiveNumber(
    dimObj?.height ?? f.height_in ?? f.heightIn ?? FLOCK_LIMITS.defaultDimsIn.height,
    "高度",
  );
  const toIn = (v: number) => toAxelWholeInches(dimValueToIn(v, dimUnit));
  const lengthIn = toIn(lengthRaw);
  const widthIn = toIn(widthRaw);
  const heightIn = toIn(heightRaw);

  if (lengthIn > FLOCK_LIMITS.dimIn.lengthMax) {
    throw new ValidationError(FLOCK_VALIDATION_MESSAGES.length);
  }
  if (widthIn > FLOCK_LIMITS.dimIn.widthMax) {
    throw new ValidationError(FLOCK_VALIDATION_MESSAGES.width);
  }
  if (heightIn > FLOCK_LIMITS.dimIn.heightMax) {
    throw new ValidationError(FLOCK_VALIDATION_MESSAGES.height);
  }
  if (
    formMode !== "logged_in_quick" &&
    !fitsFlockTrailerCargo({ palletCount, lengthIn, widthIn })
  ) {
    throw new ValidationError(FLOCK_VALIDATION_MESSAGES.linearFeet);
  }

  const registration = parseRegistrationBlock(f.registration ?? f.account);

  const optionalStr = (v: unknown): string | undefined => {
    if (typeof v !== "string") return undefined;
    const t = v.trim();
    return t || undefined;
  };

  const optionalBool = (v: unknown): boolean | undefined =>
    typeof v === "boolean" ? v : undefined;

  return {
    request_id: requestId,
    customer_id: customerId,
    pickupDate,
    pickupZip,
    deliveryZip,
    palletCount,
    totalWeightLb,
    lengthIn,
    widthIn,
    heightIn,
    registration,
    formMode,
    pickupLocationType: optionalStr(
      f.pickup_location_type ?? f.pickupLocationType,
    ),
    deliveryLocationType: optionalStr(
      f.delivery_location_type ?? f.deliveryLocationType,
    ),
    packagingType: optionalStr(f.packaging_type ?? f.packagingType),
    freightClass: optionalStr(f.freight_class ?? f.freightClass),
    description: optionalStr(f.description),
    stackable:
      typeof f.stackable === "boolean" ? f.stackable : undefined,
    turnable: typeof f.turnable === "boolean" ? f.turnable : undefined,
    additionalServices: Array.isArray(f.additional_services ?? f.additionalServices)
      ? ((f.additional_services ?? f.additionalServices) as unknown[])
          .filter((x): x is string => typeof x === "string" && x.trim().length > 0)
          .map((x) => x.trim())
      : undefined,
    vehicleTypes: Array.isArray(f.vehicle_types ?? f.vehicleTypes)
      ? ((f.vehicle_types ?? f.vehicleTypes) as unknown[])
          .filter((x): x is string => typeof x === "string" && x.trim().length > 0)
          .map((x) => x.trim())
      : undefined,
    callBeforePickup:
      typeof f.call_before_pickup === "boolean"
        ? f.call_before_pickup
        : typeof f.callBeforePickup === "boolean"
          ? f.callBeforePickup
          : undefined,
    callBeforeDelivery:
      typeof f.call_before_delivery === "boolean"
        ? f.call_before_delivery
        : typeof f.callBeforeDelivery === "boolean"
          ? f.callBeforeDelivery
          : undefined,
    pickupLiftgate: optionalBool(
      f.pickup_liftgate ?? f.pickupLiftgate,
    ),
    pickupInside: optionalBool(f.pickup_inside ?? f.pickupInside),
    pickupPalletJack: optionalBool(
      f.pickup_pallet_jack ?? f.pickupPalletJack,
    ),
    deliveryLiftgate: optionalBool(
      f.delivery_liftgate ?? f.deliveryLiftgate,
    ),
    deliveryInside: optionalBool(f.delivery_inside ?? f.deliveryInside),
    deliveryPalletJack: optionalBool(
      f.delivery_pallet_jack ?? f.deliveryPalletJack,
    ),
    pickupService: optionalStr(f.pickup_service ?? f.pickupService),
    deliveryService: optionalStr(f.delivery_service ?? f.deliveryService),
    pickupWindowStartTime: optionalStr(
      f.pickup_window_start_time ?? f.pickupWindowStartTime,
    ),
    pickupWindowEndTime: optionalStr(
      f.pickup_window_end_time ?? f.pickupWindowEndTime,
    ),
    pickupAppointmentTime: optionalStr(
      f.pickup_appointment_time ?? f.pickupAppointmentTime,
    ),
    deliveryWindowStartTime: optionalStr(
      f.delivery_window_start_time ?? f.deliveryWindowStartTime,
    ),
    deliveryWindowEndTime: optionalStr(
      f.delivery_window_end_time ?? f.deliveryWindowEndTime,
    ),
    deliveryWindowDate: optionalStr(
      f.delivery_window_date ?? f.deliveryWindowDate,
    ),
    deliveryAppointmentTime: optionalStr(
      f.delivery_appointment_time ?? f.deliveryAppointmentTime,
    ),
    deliveryAppointmentDate: optionalStr(
      f.delivery_appointment_date ?? f.deliveryAppointmentDate,
    ),
    deliveryMustArriveByDate: optionalStr(
      f.delivery_must_arrive_by_date ?? f.deliveryMustArriveByDate,
    ),
    callForDeliveryAppointment: optionalBool(
      f.call_for_delivery_appointment ?? f.callForDeliveryAppointment,
    ),
  };
}
