import dayjs from 'dayjs';
import isoWeek from 'dayjs/plugin/isoWeek';
import weekday from 'dayjs/plugin/weekday';
import type { WorkReportType } from './types';

dayjs.extend(isoWeek);
dayjs.extend(weekday);

export interface WorkReportPeriodOption {
  key: string;
  label: string;
  description: string;
  reportType: WorkReportType;
  flag?: number;
  period: {
    periodKey: string;
    periodLabel: string;
    periodStartDate: string;
    periodEndDate: string;
  };
}

export interface WorkReportResolvedPeriod {
  periodKey: string;
  periodLabel: string;
  periodStartDate: string;
  periodEndDate: string;
  flag?: number;
}

function formatRangeLabel(start: dayjs.Dayjs, end: dayjs.Dayjs) {
  return `${start.format('YYYY-MM-DD')} 至 ${end.format('YYYY-MM-DD')}`;
}

export function formatPeriodDisplayLabel(label?: string | null) {
  return String(label || '')
    .trim()
    .replace(/\s*(周报|月报|项目半月报|半月报)\s*$/u, '');
}

// 使用 ISO 周数，确保与 buildWeeklyPeriodFromDate 的计算一致
export function getIsoWeekDisplay(date: string | dayjs.Dayjs) {
  const selectedDate = dayjs(date);
  if (!selectedDate.isValid()) return '';
  // isoWeek() 返回 ISO 8601 周数（周一为一周起始）
  return `${selectedDate.format('GGGG')} 第${String(selectedDate.isoWeek()).padStart(2, '0')} 周`;
}

export function formatIsoWeekCompactLabel(date: string | dayjs.Dayjs) {
  const selectedDate = dayjs(date);
  if (!selectedDate.isValid()) return '';

  const weekDate = selectedDate.startOf('isoWeek');
  const weekYear = weekDate.add(3, 'day').format('YYYY');
  return `${weekYear}-${String(weekDate.isoWeek()).padStart(2, '0')}周`;
}

export function formatIsoWeekRangeLabel(
  startDate?: string | dayjs.Dayjs | null,
  endDate?: string | dayjs.Dayjs | null
) {
  const startLabel = startDate ? formatIsoWeekCompactLabel(startDate) : '';
  const endLabel = endDate ? formatIsoWeekCompactLabel(endDate) : '';

  if (!startLabel && !endLabel) return '';
  if (!endLabel || startLabel === endLabel) return startLabel;
  if (!startLabel) return endLabel;

  return `${startLabel} 至 ${endLabel}`;
}

/* eslint-disable-next-line max-params */
function buildPeriod(reportType: WorkReportType, start: dayjs.Dayjs, end: dayjs.Dayjs, label: string, flag?: number) {
  const startText = start.format('YYYY-MM-DD');
  const endText = end.format('YYYY-MM-DD');

  return {
    periodKey: flag ? `${reportType}-${startText}-${endText}-${flag}` : `${reportType}-${startText}-${endText}`,
    periodLabel: label,
    periodStartDate: startText,
    periodEndDate: endText
  };
}

export function buildWeeklyPeriodFromDate(date: string | dayjs.Dayjs) {
  const selectedDate = dayjs(date);
  const start = selectedDate.startOf('isoWeek');
  const end = selectedDate.endOf('isoWeek');

  return buildPeriod('weekly', start, end, formatRangeLabel(start, end));
}

export function normalizeWeeklySearchRange(periodRange?: string[] | null): string[] | undefined {
  if (!periodRange?.length) return undefined;

  const [startDate, endDate] = periodRange;
  const start = dayjs(startDate);
  const end = dayjs(endDate || startDate);

  if (!start.isValid() || !end.isValid()) {
    return periodRange ?? undefined;
  }

  return [start.startOf('isoWeek').format('YYYY-MM-DD'), end.startOf('isoWeek').format('YYYY-MM-DD')];
}

export function buildMonthlyPeriodFromMonth(month: string | dayjs.Dayjs) {
  const selectedMonth = dayjs(month);
  const start = selectedMonth.startOf('month');
  const end = selectedMonth.endOf('month');

  return buildPeriod('monthly', start, end, selectedMonth.format('YYYY-MM'));
}

export function buildProjectPeriodFromMonth(month: string | dayjs.Dayjs, flag: number) {
  const selectedMonth = dayjs(month);
  const monthStart = selectedMonth.startOf('month');

  if (flag === 2) {
    const start = monthStart.date(16);
    const end = selectedMonth.endOf('month');
    return buildPeriod('project', start, end, `${selectedMonth.format('YYYY-MM')} 下半月`, 2);
  }

  const start = monthStart.startOf('month');
  const end = monthStart.date(15);
  return buildPeriod('project', start, end, `${selectedMonth.format('YYYY-MM')} 上半月`, 1);
}

export function getWeeklyPeriodOptions(now = dayjs()): WorkReportPeriodOption[] {
  const thisWeekStart = now.startOf('isoWeek');
  const thisWeekEnd = now.endOf('isoWeek');
  const lastWeekStart = thisWeekStart.subtract(1, 'week');
  const lastWeekEnd = thisWeekEnd.subtract(1, 'week');

  return [
    {
      key: 'current-week',
      label: '本周',
      description: formatRangeLabel(thisWeekStart, thisWeekEnd),
      reportType: 'weekly',
      period: buildPeriod('weekly', thisWeekStart, thisWeekEnd, formatRangeLabel(thisWeekStart, thisWeekEnd))
    },
    {
      key: 'last-week',
      label: '上周',
      description: formatRangeLabel(lastWeekStart, lastWeekEnd),
      reportType: 'weekly',
      period: buildPeriod('weekly', lastWeekStart, lastWeekEnd, formatRangeLabel(lastWeekStart, lastWeekEnd))
    }
  ];
}

export function getMonthlyPeriodOptions(now = dayjs()): WorkReportPeriodOption[] {
  const thisMonthStart = now.startOf('month');
  const thisMonthEnd = now.endOf('month');
  const lastMonth = now.subtract(1, 'month');
  const lastMonthStart = lastMonth.startOf('month');
  const lastMonthEnd = lastMonth.endOf('month');

  return [
    {
      key: 'current-month',
      label: '本月',
      description: thisMonthStart.format('YYYY-MM'),
      reportType: 'monthly',
      period: buildPeriod('monthly', thisMonthStart, thisMonthEnd, thisMonthStart.format('YYYY-MM'))
    },
    {
      key: 'last-month',
      label: '上月',
      description: lastMonthStart.format('YYYY-MM'),
      reportType: 'monthly',
      period: buildPeriod('monthly', lastMonthStart, lastMonthEnd, lastMonthStart.format('YYYY-MM'))
    }
  ];
}

export function getProjectPeriodOptions(now = dayjs()): WorkReportPeriodOption[] {
  const currentMonthStart = now.startOf('month');
  const currentMonthEnd = now.endOf('month');
  const currentFirstHalfEnd = currentMonthStart.date(15);
  const currentSecondHalfStart = currentMonthStart.date(16);
  const previousMonth = now.subtract(1, 'month');
  const previousMonthStart = previousMonth.startOf('month');
  const previousMonthEnd = previousMonth.endOf('month');
  const previousSecondHalfStart = previousMonthStart.date(16);
  const isCurrentFirstHalf = now.date() <= 15;

  const currentOption: WorkReportPeriodOption = isCurrentFirstHalf
    ? {
        key: 'current-first-half',
        label: '上半月',
        description: `${now.format('YYYY-MM')} 上半月`,
        reportType: 'project',
        flag: 1,
        period: buildPeriod('project', currentMonthStart, currentFirstHalfEnd, `${now.format('YYYY-MM')} 上半月`, 1)
      }
    : {
        key: 'current-second-half',
        label: '下半月',
        description: `${now.format('YYYY-MM')} 下半月`,
        reportType: 'project',
        flag: 2,
        period: buildPeriod('project', currentSecondHalfStart, currentMonthEnd, `${now.format('YYYY-MM')} 下半月`, 2)
      };

  const previousOption: WorkReportPeriodOption = isCurrentFirstHalf
    ? {
        key: 'previous-second-half',
        label: '下半月',
        description: `${previousMonth.format('YYYY-MM')} 下半月`,
        reportType: 'project',
        flag: 2,
        period: buildPeriod(
          'project',
          previousSecondHalfStart,
          previousMonthEnd,
          `${previousMonth.format('YYYY-MM')} 下半月`,
          2
        )
      }
    : {
        key: 'previous-first-half',
        label: '上半月',
        description: `${now.format('YYYY-MM')} 上半月`,
        reportType: 'project',
        flag: 1,
        period: buildPeriod('project', currentMonthStart, currentFirstHalfEnd, `${now.format('YYYY-MM')} 上半月`, 1)
      };

  return [currentOption, previousOption];
}

export function getReportTypePeriodOptions(now = dayjs()) {
  return {
    weekly: getWeeklyPeriodOptions(now),
    monthly: getMonthlyPeriodOptions(now),
    project: getProjectPeriodOptions(now)
  } as const;
}

type PeriodRange = string[] | null | undefined;

interface ResolveWorkReportSummaryPeriodOptions {
  currentRow?: Partial<WorkReportResolvedPeriod> | null;
  periodRange?: PeriodRange;
  flag?: number | null;
}

function getRangeReferenceDate(periodRange?: PeriodRange) {
  const [, endDate] = periodRange || [];
  return endDate || periodRange?.[0] || '';
}

function inferProjectSummaryFlag(referenceDate: string, explicitFlag?: number | null) {
  if (explicitFlag === 1 || explicitFlag === 2) {
    return explicitFlag;
  }

  const selectedDate = dayjs(referenceDate);
  if (selectedDate.isValid()) {
    return selectedDate.date() > 15 ? 2 : 1;
  }

  return getProjectPeriodOptions()[0]?.flag || 1;
}

export function resolveWorkReportSummaryPeriod(
  reportType: WorkReportType,
  options: ResolveWorkReportSummaryPeriodOptions = {}
): WorkReportResolvedPeriod {
  const { currentRow, periodRange, flag } = options;

  if (currentRow?.periodKey && currentRow.periodStartDate && currentRow.periodEndDate) {
    return {
      periodKey: currentRow.periodKey,
      periodLabel: currentRow.periodLabel || '',
      periodStartDate: currentRow.periodStartDate,
      periodEndDate: currentRow.periodEndDate,
      flag: currentRow.flag
    };
  }

  const referenceDate = getRangeReferenceDate(periodRange);
  const fallbackNow = dayjs();

  if (reportType === 'weekly') {
    return referenceDate ? buildWeeklyPeriodFromDate(referenceDate) : buildWeeklyPeriodFromDate(fallbackNow);
  }

  if (reportType === 'monthly') {
    return referenceDate ? buildMonthlyPeriodFromMonth(referenceDate) : buildMonthlyPeriodFromMonth(fallbackNow);
  }

  if (referenceDate) {
    const resolvedFlag = inferProjectSummaryFlag(referenceDate, flag);
    return {
      ...buildProjectPeriodFromMonth(referenceDate, resolvedFlag),
      flag: resolvedFlag
    };
  }

  const fallbackOption = getProjectPeriodOptions(fallbackNow)[0];

  return {
    ...fallbackOption.period,
    flag: fallbackOption.flag
  };
}
