/**
 * 文件职责：自提设置页面纯函数工具。
 * 1. 负责克隆、格式化、校验、排序等纯逻辑。
 * 2. 不直接请求接口，不生成 mock 预览数据。
 */
import type {
  PickupBasicSettingsDto,
  PickupFineRuleDto,
  PickupPreviewDayDto,
  PickupSlotDto,
  PickupWeekDay,
} from '#/api/store-pickup';
import type { PickupSettingsSnapshot } from '#/views/store/pickup/types';

import {
  ALL_WEEK_DAYS,
  WEEKDAY_ONLY,
  WEEKDAY_OPTIONS,
  WEEKEND_ONLY,
} from './constants';

/** 深拷贝基础设置对象。 */
export function cloneBasicSettings(source: PickupBasicSettingsDto) {
  return { ...source };
}

/** 深拷贝大时段列表。 */
export function cloneBigSlots(source: PickupSlotDto[]) {
  return source.map((item) => ({
    ...item,
    dayOfWeeks: [...item.dayOfWeeks],
  }));
}

/** 深拷贝精细规则。 */
export function cloneFineRule(source: PickupFineRuleDto) {
  return {
    ...source,
    dayOfWeeks: [...source.dayOfWeeks],
  };
}

/** 深拷贝预览列表。 */
export function clonePreviewDays(source: PickupPreviewDayDto[]) {
  return source.map((day) => ({
    ...day,
    slots: day.slots.map((slot) => ({ ...slot })),
  }));
}

/** 组装快照，用于重置场景。 */
export function createSettingsSnapshot(payload: {
  basicSettings: PickupBasicSettingsDto;
  bigSlots: PickupSlotDto[];
  fineRule: PickupFineRuleDto;
  mode: 'big' | 'fine';
  previewDays: PickupPreviewDayDto[];
}): PickupSettingsSnapshot {
  return {
    mode: payload.mode,
    basicSettings: cloneBasicSettings(payload.basicSettings),
    bigSlots: cloneBigSlots(payload.bigSlots),
    fineRule: cloneFineRule(payload.fineRule),
    previewDays: clonePreviewDays(payload.previewDays),
  };
}

/** HH:mm 转分钟。 */
export function parseTimeToMinutes(time: string) {
  const matched = /^(\d{2}):(\d{2})$/.exec(time);
  if (!matched) return Number.NaN;
  return Number(matched[1]) * 60 + Number(matched[2]);
}

/** 按开始时间升序排序时段。 */
export function sortSlots(source: PickupSlotDto[]) {
  return cloneBigSlots(source).toSorted((a, b) => {
    const diff =
      parseTimeToMinutes(a.startTime) - parseTimeToMinutes(b.startTime);
    if (diff !== 0) return diff;
    return a.name.localeCompare(b.name);
  });
}

/** 生成时段唯一 ID。 */
export function createSlotId() {
  return `pickup-slot-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
}

/** 根据星期数组格式化展示文案。 */
export function formatDayOfWeeksText(dayOfWeeks: PickupWeekDay[]) {
  const sorted = [...new Set(dayOfWeeks)].toSorted((a, b) => a - b);
  if (isSameDaySet(sorted, ALL_WEEK_DAYS)) return '每天';
  if (isSameDaySet(sorted, WEEKDAY_ONLY)) return '周一至周五';
  if (isSameDaySet(sorted, WEEKEND_ONLY)) return '周六周日';
  return sorted
    .map(
      (day) => WEEKDAY_OPTIONS.find((item) => item.value === day)?.label ?? '',
    )
    .filter(Boolean)
    .join('、');
}

/** 计算预约使用率百分比。 */
export function calcReservedPercent(slot: PickupSlotDto) {
  if (slot.capacity <= 0) return 0;
  const ratio = (Math.max(0, slot.reservedCount) / slot.capacity) * 100;
  return Math.min(100, Math.round(ratio));
}

/** 校验新增/编辑时段。 */
export function validateSlotForm(payload: {
  capacity: number;
  cutoffMinutes: number;
  dayOfWeeks: PickupWeekDay[];
  endTime: string;
  name: string;
  slotId?: string;
  slots: PickupSlotDto[];
  startTime: string;
}) {
  // 1. 必填与基础值校验。
  if (!payload.name.trim()) return '请输入时段名称';
  if (payload.dayOfWeeks.length === 0) return '请至少选择一个适用星期';

  const start = parseTimeToMinutes(payload.startTime);
  const end = parseTimeToMinutes(payload.endTime);
  if (!Number.isFinite(start) || !Number.isFinite(end))
    return '请选择正确的时间';
  if (end <= start) return '结束时间必须晚于开始时间';
  if (payload.cutoffMinutes < 0) return '截止分钟不能小于 0';
  if (payload.capacity < 0) return '容量不能小于 0';

  // 2. 同星期时段重叠校验。
  const hasOverlap = payload.slots.some((item) => {
    if (payload.slotId && item.id === payload.slotId) return false;
    const overlapDays = item.dayOfWeeks.filter((day) =>
      payload.dayOfWeeks.includes(day),
    );
    if (overlapDays.length === 0) return false;

    const itemStart = parseTimeToMinutes(item.startTime);
    const itemEnd = parseTimeToMinutes(item.endTime);
    return !(end <= itemStart || start >= itemEnd);
  });
  if (hasOverlap) return '同一星期存在时间重叠，请调整后重试';

  return '';
}

function isSameDaySet(a: PickupWeekDay[], b: PickupWeekDay[]) {
  if (a.length !== b.length) return false;
  return a.every((day, index) => day === b[index]);
}
