/**
 * 营业时间页面纯函数工具集：
 * 仅包含格式化、归一化、样式映射、校验，不依赖组件状态。
 */
import type { DayHoursDto, HolidayDto, TimeSlotDto } from '#/api/store-hours';

import { HolidayType, SlotType } from '#/api/store-hours';

import {
  DAY_INDEXES,
  DEFAULT_HOLIDAY_COLOR,
  DEFAULT_SLOT_COLOR,
  HOLIDAY_COLORS,
  SLOT_COLORS,
  SLOT_TYPE_LABELS,
} from './constants';

// 1. 基础格式化工具。
export function createSlotId() {
  return `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
}

export function getTodayDate() {
  const today = new Date();
  const month = String(today.getMonth() + 1).padStart(2, '0');
  const date = String(today.getDate()).padStart(2, '0');
  return `${today.getFullYear()}-${month}-${date}`;
}

export function toDateOnly(value?: string) {
  if (!value) return '';
  return String(value).slice(0, 10);
}

export function toTimeHHmm(value?: string) {
  if (!value) return '';
  const matched = /(\d{2}:\d{2})/.exec(value);
  return matched?.[1] ?? '';
}

export function parseTimeToMinutes(time: string) {
  const matched = /^([01]\d|2[0-3]):([0-5]\d)$/.exec(time);
  if (!matched) return null;
  return Number(matched[1]) * 60 + Number(matched[2]);
}

// 2. 数据归一化与排序。
export function sortSlots(slots: TimeSlotDto[]) {
  return [...slots].toSorted((a, b) => {
    const startA = parseTimeToMinutes(a.startTime) ?? 0;
    const startB = parseTimeToMinutes(b.startTime) ?? 0;
    if (startA !== startB) return startA - startB;
    return Number(a.type) - Number(b.type);
  });
}

export function normalizeSlots(slots: TimeSlotDto[]) {
  return sortSlots(
    (slots ?? []).map((slot) => {
      const slotType = Number(slot.type) as SlotType;
      return {
        id: slot.id || createSlotId(),
        type: SLOT_TYPE_LABELS[slotType] ? slotType : SlotType.Business,
        startTime: toTimeHHmm(slot.startTime) || '09:00',
        endTime: toTimeHHmm(slot.endTime) || '22:00',
        capacity:
          slotType === SlotType.Delivery && slot.capacity !== undefined
            ? Number(slot.capacity)
            : undefined,
        remark: slot.remark || '',
      } as TimeSlotDto;
    }),
  );
}

export function normalizeWeeklyHours(source: DayHoursDto[]) {
  const dayMap = new Map<number, DayHoursDto>();
  for (const item of source ?? []) {
    const dayOfWeek = Number(item.dayOfWeek);
    if (!Number.isInteger(dayOfWeek) || dayOfWeek < 0 || dayOfWeek > 6)
      continue;
    const slots = normalizeSlots(item.slots ?? []);
    dayMap.set(dayOfWeek, {
      dayOfWeek,
      isOpen: typeof item.isOpen === 'boolean' ? item.isOpen : slots.length > 0,
      slots,
    });
  }

  return DAY_INDEXES.map((dayOfWeek) => {
    return (
      dayMap.get(dayOfWeek) ?? {
        dayOfWeek,
        isOpen: false,
        slots: [],
      }
    );
  });
}

export function normalizeHolidays(source: HolidayDto[]) {
  return [...(source ?? [])]
    .map((holiday) => ({
      id: String(holiday.id || createSlotId()),
      startDate: toDateOnly(holiday.startDate),
      endDate: toDateOnly(holiday.endDate || holiday.startDate),
      type:
        Number(holiday.type) === HolidayType.Special
          ? HolidayType.Special
          : HolidayType.Closed,
      startTime: toTimeHHmm(holiday.startTime),
      endTime: toTimeHHmm(holiday.endTime),
      reason: holiday.reason || '',
      remark: holiday.remark || '',
    }))
    .toSorted((a, b) => {
      const dateCompare = a.startDate.localeCompare(b.startDate);
      if (dateCompare !== 0) return dateCompare;
      return a.id.localeCompare(b.id);
    });
}

export function cloneWeeklyHours(source: DayHoursDto[]) {
  return normalizeWeeklyHours(source).map((day) => ({
    ...day,
    slots: day.slots.map((slot) => ({ ...slot })),
  }));
}

// 3. 展示映射工具（标签、颜色、文案）。
export function getSlotTypeLabel(type: SlotType) {
  return SLOT_TYPE_LABELS[type] || '未知';
}

export function getSlotStyle(type: SlotType) {
  const color = SLOT_COLORS[type] ?? DEFAULT_SLOT_COLOR;
  return {
    background: color.bg,
    borderColor: color.border,
    color: color.text,
  };
}

export function getHolidayTagStyle(type: HolidayType) {
  const color = HOLIDAY_COLORS[type] ?? DEFAULT_HOLIDAY_COLOR;
  return {
    background: color.bg,
    color: color.text,
  };
}

export function getLegendDotColor(type: SlotType) {
  return (SLOT_COLORS[type] ?? DEFAULT_SLOT_COLOR).dot;
}

export function getHolidayTypeText(type: HolidayType) {
  return type === HolidayType.Special ? '特殊营业' : '休息';
}

export function formatHolidayDate(holiday: HolidayDto) {
  const start = toDateOnly(holiday.startDate);
  const end = toDateOnly(holiday.endDate || holiday.startDate);
  if (!end || start === end) return start;
  return `${start} ~ ${end}`;
}

export function formatHolidayTime(holiday: HolidayDto) {
  if (holiday.type === HolidayType.Closed) return '全天';
  const start = toTimeHHmm(holiday.startTime);
  const end = toTimeHHmm(holiday.endTime);
  return start && end ? `${start} - ${end}` : '--';
}

export function getSlotTypePillClass(type: SlotType) {
  if (type === SlotType.Business) return 'tp-biz';
  if (type === SlotType.Delivery) return 'tp-del';
  return 'tp-pick';
}

// 4. 业务校验工具（单时段与日内冲突）。
export function validateSlot(slot: TimeSlotDto) {
  const start = parseTimeToMinutes(slot.startTime);
  const end = parseTimeToMinutes(slot.endTime);
  if (start === null || end === null) {
    return '开始时间或结束时间格式不正确';
  }
  if (start >= end) {
    return '开始时间必须早于结束时间';
  }
  if (slot.type === SlotType.Delivery) {
    const capacity = Number(slot.capacity);
    if (!Number.isInteger(capacity) || capacity <= 0) {
      return '配送时段容量必须为正整数';
    }
  }
  return null;
}

export function validateDaySlots(slots: TimeSlotDto[]) {
  for (const slot of slots) {
    const slotError = validateSlot(slot);
    if (slotError) return slotError;
  }

  for (const type of [SlotType.Business, SlotType.Delivery, SlotType.Pickup]) {
    const sameTypeSlots = sortSlots(slots.filter((slot) => slot.type === type));
    for (let index = 1; index < sameTypeSlots.length; index++) {
      const prevSlot = sameTypeSlots[index - 1];
      const currentSlot = sameTypeSlots[index];
      if (!prevSlot || !currentSlot) continue;

      const prevEnd = parseTimeToMinutes(prevSlot.endTime) ?? 0;
      const currentStart = parseTimeToMinutes(currentSlot.startTime) ?? 0;
      if (currentStart < prevEnd) {
        return `${getSlotTypeLabel(type)}时段存在重叠，请调整`;
      }
    }
  }

  return null;
}
