import { isChinaWorkday } from './china-workday-calendar';

export const WORK_HOURS = {
  morningStart: 9,
  morningEnd: 12,
  afternoonStart: 13,
  afternoonEnd: 18,
  hoursPerDay: 8,
  skipWeekends: true,
} as const;

const MS_PER_HOUR = 60 * 60 * 1000;

function isWeekend(d: Date): boolean {
  const wd = d.getDay();
  return wd === 0 || wd === 6;
}

function clamp(v: number, lo: number, hi: number): number {
  return Math.max(lo, Math.min(hi, v));
}

function dayBound(d: Date, hourFloat: number): Date {
  const h = Math.floor(hourFloat);
  const m = Math.round((hourFloat - h) * 60);
  const r = new Date(d);
  r.setHours(h, m, 0, 0);
  return r;
}

function dayOverlapHours(start: Date, end: Date, day: Date): number {
  if (WORK_HOURS.skipWeekends && !isChinaWorkday(day)) return 0;
  const morningStart = dayBound(day, WORK_HOURS.morningStart);
  const morningEnd = dayBound(day, WORK_HOURS.morningEnd);
  const afternoonStart = dayBound(day, WORK_HOURS.afternoonStart);
  const afternoonEnd = dayBound(day, WORK_HOURS.afternoonEnd);
  const morning = clamp(end.getTime(), morningStart.getTime(), morningEnd.getTime())
    - clamp(start.getTime(), morningStart.getTime(), morningEnd.getTime());
  const afternoon = clamp(end.getTime(), afternoonStart.getTime(), afternoonEnd.getTime())
    - clamp(start.getTime(), afternoonStart.getTime(), afternoonEnd.getTime());
  return Math.max(0, morning + afternoon) / MS_PER_HOUR;
}

/**
 * 计算 ISO 时间区间内属于工作时段的小时数
 *
 * 工作时段：9:00–12:00 + 13:00–18:00（共 8h/天），周末跳过
 * 精度：0.5h
 *
 * 验证用例（注释式，供日后接 vitest 迁移）：
 * - 单日 11:00→14:00 = 1.5h（午休 12:00–13:00 不算）
 * - 单日 09:00→18:00 = 8h
 * - 跨天 1月1日 09:00 → 1月2日 14:00 = 8 + 1 = 9h
 *   （注：旧需求是 9:00–18:00 无午休=14h，现按 8h/天口径，结果 9h）
 * - 跨周末 周五 17:00 → 周一 11:00 = 1 + 2 = 3h
 * - 全在午休 12:30→13:00 = 0h
 * - 全在周末 周六全天 = 0h
 * - 负区间 / 非法 ISO = 0
 */
function calcWorkHoursRaw(startISO: string, endISO: string): number {
  if (!startISO || !endISO) return 0;
  const start = new Date(startISO);
  const end = new Date(endISO);
  if (isNaN(start.getTime()) || isNaN(end.getTime())) return 0;
  if (end.getTime() <= start.getTime()) return 0;

  let total = 0;
  const cursor = new Date(start);
  cursor.setHours(0, 0, 0, 0);
  const endDay = new Date(end);
  endDay.setHours(0, 0, 0, 0);

  while (cursor.getTime() <= endDay.getTime()) {
    total += dayOverlapHours(start, end, cursor);
    cursor.setDate(cursor.getDate() + 1);
  }

  return total;
}

export function calcWorkHours(startISO: string, endISO: string): number {
  const total = calcWorkHoursRaw(startISO, endISO);
  return Math.round(total * 2) / 2;
}

/**
 * 把小时数格式化为 "Xh（Y天）"，Y 保留 1 位小数（整数则不带小数）
 */
export function formatWorkHours(hours: number): string {
  if (!isFinite(hours) || hours <= 0) return '0h（0天）';
  const days = hours / WORK_HOURS.hoursPerDay;
  const dayStr = Number.isInteger(days) ? String(days) : days.toFixed(1).replace(/\.0$/, '');
  return `${hours}h（${dayStr}天）`;
}

/**
 * 简短版："Xh"，不带天数（用于横向空间紧张的列表行）
 */
export function formatWorkHoursShort(hours: number): string {
  if (!isFinite(hours) || hours <= 0) return '0h';
  return `${hours}h`;
}

/**
 * 计算真实经过时长，而不是工作时段内时长。
 *
 * 用于“实际耗时”口径：按开始/结束时间戳直接相减，精度 0.5h；
 * 只要有正向耗时，最低按 0.5h 计，避免 30 分钟内工作被显示为 0。
 */
// 实际耗时只统计中国工作日历内的工作时段；加班通过 overtime 记录单独计入。
export function calcActualElapsedHours(startISO?: string | null, endISO?: string | null): number {
  if (!startISO || !endISO) return 0;
  const hours = calcWorkHoursRaw(startISO, endISO);
  if (hours <= 0) return 0;
  return Math.max(0.5, Math.round(hours * 2) / 2);
}

function formatNaturalDays(hours: number): string {
  if (!isFinite(hours) || hours <= 0) return '0天';
  const days = hours / 24;
  if (days < 0.1) return `${Number(days.toFixed(2))}天`;
  return `${Number.isInteger(days) ? String(days) : days.toFixed(1).replace(/\.0$/, '')}天`;
}

/**
 * 实际耗时显示，天数按自然日 24h 换算。
 */
export function formatActualDuration(hours: number): string {
  if (!isFinite(hours) || hours <= 0) return '0h（0天）';
  return `${hours}h（${formatNaturalDays(hours)}）`;
}

/**
 * 仅天数版："Y天"
 */
export function formatWorkDays(hours: number): string {
  if (!isFinite(hours) || hours <= 0) return '0天';
  const days = hours / WORK_HOURS.hoursPerDay;
  const dayStr = Number.isInteger(days) ? String(days) : days.toFixed(1).replace(/\.0$/, '');
  return `${dayStr}天`;
}

/**
 * 给定开始 ISO + 工时小时数，返回结束 ISO（备用：旧 estimateHours 反推 expectedEndAt）
 * 算法：从开始时间起，按工作时段累加，到达目标小时数即返回。
 */
export function addWorkHours(startISO: string, hours: number): string {
  const start = new Date(startISO);
  if (isNaN(start.getTime()) || hours <= 0) return startISO;
  let remaining = hours;
  const cursor = new Date(start);
  while (remaining > 0) {
    const day = new Date(cursor);
    day.setHours(0, 0, 0, 0);
    if (WORK_HOURS.skipWeekends && !isChinaWorkday(day)) {
      cursor.setDate(cursor.getDate() + 1);
      cursor.setHours(WORK_HOURS.morningStart, 0, 0, 0);
      continue;
    }
    const morningStart = dayBound(day, WORK_HOURS.morningStart);
    const morningEnd = dayBound(day, WORK_HOURS.morningEnd);
    const afternoonStart = dayBound(day, WORK_HOURS.afternoonStart);
    const afternoonEnd = dayBound(day, WORK_HOURS.afternoonEnd);
    const segments: Array<[Date, Date]> = [
      [morningStart, morningEnd],
      [afternoonStart, afternoonEnd],
    ];
    let advanced = false;
    for (const [segStart, segEnd] of segments) {
      if (cursor.getTime() >= segEnd.getTime()) continue;
      const segBegin = cursor.getTime() < segStart.getTime() ? segStart : cursor;
      const availableH = (segEnd.getTime() - segBegin.getTime()) / MS_PER_HOUR;
      if (availableH <= 0) continue;
      if (remaining <= availableH) {
        const finalMs = segBegin.getTime() + remaining * MS_PER_HOUR;
        return new Date(finalMs).toISOString();
      }
      remaining -= availableH;
      cursor.setTime(segEnd.getTime());
      advanced = true;
    }
    if (!advanced) {
      cursor.setDate(cursor.getDate() + 1);
      cursor.setHours(WORK_HOURS.morningStart, 0, 0, 0);
    } else if (cursor.getTime() >= dayBound(day, WORK_HOURS.afternoonEnd).getTime()) {
      cursor.setDate(cursor.getDate() + 1);
      cursor.setHours(WORK_HOURS.morningStart, 0, 0, 0);
    }
  }
  return cursor.toISOString();
}

/**
 * 把 datetime-local 输入值（如 "2026-06-16T09:00"）规范化为本地 ISO（含秒和毫秒）
 */
export function localToISO(local: string): string {
  if (!local) return '';
  const d = new Date(local);
  return isNaN(d.getTime()) ? '' : d.toISOString();
}

/**
 * 把 ISO 时间转成 datetime-local 输入值
 */
export function isoToLocal(iso: string): string {
  if (!iso) return '';
  const d = new Date(iso);
  if (isNaN(d.getTime())) return '';
  const pad = (n: number) => String(n).padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}

/**
 * 友好显示：MM-DD HH:mm
 */
export function formatShortTime(iso: string): string {
  if (!iso) return '';
  const d = new Date(iso);
  if (isNaN(d.getTime())) return '';
  const pad = (n: number) => String(n).padStart(2, '0');
  return `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
}

export interface TimeInterval {
  start: string;
  end: string;
}

/**
 * 合并多个时间区间到工作时段内的总小时数（不重复计数）
 *
 * 算法：按 start 排序后扫描，重叠区间合并 end，对每个合并后的区间调 calcWorkHours 累加
 * 用例：A(9-11) + B(10-12) → 合并为 9-12 = 3h
 */
export function mergeWorkHours(intervals: TimeInterval[]): number {
  const valid = intervals
    .filter((i) => i.start && i.end)
    .map((i) => ({ start: new Date(i.start).getTime(), end: new Date(i.end).getTime() }))
    .filter((i) => !isNaN(i.start) && !isNaN(i.end) && i.end > i.start)
    .sort((a, b) => a.start - b.start);

  if (valid.length === 0) return 0;

  const merged: Array<{ start: number; end: number }> = [];
  let cur = { ...valid[0] };
  for (let i = 1; i < valid.length; i++) {
    const next = valid[i];
    if (next.start <= cur.end) {
      cur.end = Math.max(cur.end, next.end);
    } else {
      merged.push(cur);
      cur = { ...next };
    }
  }
  merged.push(cur);

  let total = 0;
  for (const m of merged) {
    total += calcWorkHours(new Date(m.start).toISOString(), new Date(m.end).toISOString());
  }
  return Math.round(total * 2) / 2;
}

/**
 * 双口径汇总：
 * - calendarHours：合并所有重叠区间后的日历耗时（看版本实际走了几天）
 * - manhours：单条独立累加的人力投入（看总人力成本）
 */
export function calcTwoMetrics(intervals: TimeInterval[]): {
  calendarHours: number;
  manhours: number;
} {
  const calendarHours = mergeWorkHours(intervals);
  let manhours = 0;
  for (const i of intervals) {
    if (!i.start || !i.end) continue;
    manhours += calcWorkHours(i.start, i.end);
  }
  return { calendarHours, manhours: Math.round(manhours * 2) / 2 };
}
