/**
 * 文件职责：员工排班页面纯函数工具。
 * 1. 负责克隆、归一化、格式化等无副作用逻辑。
 * 2. 负责排班矩阵与周视图数据转换。
 */
import type {
  ShiftType,
  StaffDayShiftDto,
  StoreShiftTemplatesDto,
} from '#/api/store-staff';
import type {
  StaffEditorFormState,
  StaffFilterState,
  WeekEditorRow,
} from '#/views/store/staff/types';

/** 深拷贝模板。 */
export function cloneTemplates(
  source: StoreShiftTemplatesDto,
): StoreShiftTemplatesDto {
  return {
    morning: { ...source.morning },
    evening: { ...source.evening },
    full: { ...source.full },
  };
}

/** 深拷贝单员工周排班。 */
export function cloneShifts(source: StaffDayShiftDto[]) {
  return source.map((item) => ({ ...item }));
}

/** 深拷贝排班映射。 */
export function cloneScheduleMap(source: Record<string, StaffDayShiftDto[]>) {
  const next: Record<string, StaffDayShiftDto[]> = {};
  for (const [staffId, shifts] of Object.entries(source)) {
    next[staffId] = cloneShifts(shifts);
  }
  return next;
}

/** 深拷贝筛选表单。 */
export function cloneFilterState(source: StaffFilterState): StaffFilterState {
  return {
    keyword: source.keyword,
    roleType: source.roleType,
    status: source.status,
    page: source.page,
    pageSize: source.pageSize,
  };
}

/** 深拷贝员工编辑表单。 */
export function cloneStaffForm(
  source: StaffEditorFormState,
): StaffEditorFormState {
  return {
    id: source.id,
    name: source.name,
    phone: source.phone,
    email: source.email,
    roleType: source.roleType,
    status: source.status,
    permissions: [...source.permissions],
  };
}

/** 生成指定班次默认时间。 */
export function resolveShiftTimeByType(
  shiftType: ShiftType,
  templates: StoreShiftTemplatesDto,
) {
  if (shiftType === 'off') {
    return {
      startTime: '',
      endTime: '',
    };
  }
  const template = templates[shiftType];
  return {
    startTime: template.startTime,
    endTime: template.endTime,
  };
}

/** 按班次类型构建单日排班（总是使用模板时间）。 */
export function buildDayShiftByType(payload: {
  dayOfWeek: number;
  shiftType: ShiftType;
  templates: StoreShiftTemplatesDto;
}): StaffDayShiftDto {
  if (payload.shiftType === 'off') {
    return {
      dayOfWeek: payload.dayOfWeek,
      shiftType: 'off',
      startTime: '',
      endTime: '',
    };
  }

  const template = payload.templates[payload.shiftType];
  return {
    dayOfWeek: payload.dayOfWeek,
    shiftType: payload.shiftType,
    startTime: template.startTime,
    endTime: template.endTime,
  };
}

/** 归一化单日排班。 */
export function normalizeDayShift(payload: {
  dayOfWeek: number;
  fallback?: StaffDayShiftDto;
  shift: Partial<StaffDayShiftDto>;
  templates: StoreShiftTemplatesDto;
}) {
  const fallbackShift = payload.fallback;
  const shiftType = normalizeShiftType(
    payload.shift.shiftType,
    fallbackShift?.shiftType ?? 'off',
  );

  if (shiftType === 'off') {
    return {
      dayOfWeek: payload.dayOfWeek,
      shiftType,
      startTime: '',
      endTime: '',
    } satisfies StaffDayShiftDto;
  }

  const templateTime = resolveShiftTimeByType(shiftType, payload.templates);
  return {
    dayOfWeek: payload.dayOfWeek,
    shiftType,
    startTime: normalizeTime(
      payload.shift.startTime,
      payload.fallback?.startTime || templateTime.startTime,
    ),
    endTime: normalizeTime(
      payload.shift.endTime,
      payload.fallback?.endTime || templateTime.endTime,
    ),
  } satisfies StaffDayShiftDto;
}

/** 归一化周排班数组（仅保留真实配置的天）。 */
export function normalizeSparseWeekShifts(payload: {
  shifts: Partial<StaffDayShiftDto>[];
  templates: StoreShiftTemplatesDto;
}) {
  const shiftMap = new Map<number, StaffDayShiftDto>();
  for (const shift of payload.shifts) {
    const dayOfWeek = Number(shift.dayOfWeek);
    if (!Number.isInteger(dayOfWeek) || dayOfWeek < 0 || dayOfWeek > 6) {
      continue;
    }

    shiftMap.set(
      dayOfWeek,
      normalizeDayShift({
        dayOfWeek,
        shift,
        templates: payload.templates,
      }),
    );
  }

  return [...shiftMap.values()].toSorted((a, b) => a.dayOfWeek - b.dayOfWeek);
}

/** 将员工排班矩阵转为可编辑周视图行。 */
export function buildWeekEditorRows(payload: {
  scheduleMap: Record<string, StaffDayShiftDto[]>;
  staffs: Array<{
    id: string;
    name: string;
    roleType: WeekEditorRow['roleType'];
    status: WeekEditorRow['status'];
  }>;
}) {
  return payload.staffs.map((staff) => ({
    staffId: staff.id,
    staffName: staff.name,
    roleType: staff.roleType,
    status: staff.status,
    shifts: cloneShifts(payload.scheduleMap[staff.id] ?? []),
  }));
}

/** 更新周视图某员工某天班次。 */
export function updateWeekRowShift(payload: {
  dayOfWeek: number;
  nextShiftType: ShiftType;
  row: WeekEditorRow;
  templates: StoreShiftTemplatesDto;
}) {
  const nextShift = buildDayShiftByType({
    dayOfWeek: payload.dayOfWeek,
    shiftType: payload.nextShiftType,
    templates: payload.templates,
  });

  return {
    ...payload.row,
    shifts: [
      ...payload.row.shifts
        .filter((item) => item.dayOfWeek !== payload.dayOfWeek)
        .map((item) => ({ ...item })),
      nextShift,
    ].toSorted((a, b) => a.dayOfWeek - b.dayOfWeek),
  };
}

/** 归一化班次类型。 */
export function normalizeShiftType(
  value: unknown,
  fallback: ShiftType,
): ShiftType {
  if (
    value === 'morning' ||
    value === 'evening' ||
    value === 'full' ||
    value === 'off'
  ) {
    return value;
  }
  return fallback;
}

/** 归一化时间字符串（HH:mm）。 */
export function normalizeTime(value: unknown, fallback: string) {
  const input = typeof value === 'string' ? value : '';
  const matched = /^(\d{2}):(\d{2})$/.exec(input);
  if (!matched) {
    return fallback;
  }
  const hour = Number(matched[1]);
  const minute = Number(matched[2]);
  if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
    return fallback;
  }
  return `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
}

/** 获取当前周一日期。 */
export function getCurrentWeekStartDate(baseDate = new Date()) {
  const date = new Date(baseDate);
  const weekDay = date.getDay();
  const diff = weekDay === 0 ? -6 : 1 - weekDay;
  date.setDate(date.getDate() + diff);
  return toDateOnly(date);
}

/** 日期转 yyyy-MM-dd。 */
export function toDateOnly(date: Date) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
}

/** 手机号脱敏展示。 */
export function maskPhone(phone: string) {
  const normalized = String(phone || '').replaceAll(/\D/g, '');
  if (normalized.length < 7) return phone;
  return `${normalized.slice(0, 3)}****${normalized.slice(-4)}`;
}

/** 根据姓名提取头像字符。 */
export function resolveAvatarText(name: string) {
  const normalized = String(name || '').trim();
  if (!normalized) return '?';
  return normalized.slice(0, 1).toUpperCase();
}

/** 获取班次展示时间。 */
export function formatShiftTimeText(shift: StaffDayShiftDto) {
  if (shift.shiftType === 'off') return '休息';
  return `${shift.startTime}-${shift.endTime}`;
}
