import type { CampusId, CampusInfo } from '@/shared/types/app';
import type {
  CampusAttendanceEntryDraft,
  CampusAttendanceConfigViewModel,
  CampusAttendanceOverallStats,
  CampusAttendancePrintInput,
  CampusAttendanceStats,
  CampusAttendanceSummaryViewModel,
} from '@/business/campus-attendance/types';

export function getWeekStart(date: Date): string {
  const weekStart = new Date(date);
  const day = weekStart.getDay();
  const diff = weekStart.getDate() - day + (day === 0 ? -6 : 1);
  weekStart.setDate(diff);
  return weekStart.toISOString().split('T')[0];
}

export function getWeekEnd(date: Date): string {
  const weekEnd = new Date(date);
  const day = weekEnd.getDay();
  const diff = weekEnd.getDate() - day + (day === 0 ? 0 : 5);
  weekEnd.setDate(diff);
  return weekEnd.toISOString().split('T')[0];
}

export function getToday(): string {
  return new Date().toISOString().split('T')[0];
}

export function formatAttendanceDate(date: string): string {
  const displayDate = new Date(`${date}T12:00:00`);
  return displayDate.toLocaleDateString('en-US', {
    weekday: 'short',
    month: 'short',
    day: 'numeric',
    year: 'numeric',
  });
}

export function parseAttendanceCount(value: string): number | null {
  const parsed = Number.parseInt(value, 10);
  return Number.isNaN(parsed) ? null : parsed;
}

export function buildAttendanceEntryInput(draft: CampusAttendanceEntryDraft, campusId: CampusId) {
  const totalEnrolled = parseAttendanceCount(draft.enrolled);
  const totalPresent = parseAttendanceCount(draft.present);
  const totalAbsent = parseAttendanceCount(draft.absent);
  const totalTardy = parseAttendanceCount(draft.tardy) ?? 0;

  if (totalEnrolled === null || totalPresent === null || totalAbsent === null || totalEnrolled <= 0) {
    return null;
  }

  return {
    campusId,
    date: draft.date,
    totalEnrolled,
    totalPresent,
    totalAbsent,
    totalTardy,
    notes: draft.notes.trim() || null,
  };
}

export function getDraftAttendancePercentage(draft: CampusAttendanceEntryDraft): number | null {
  const totalEnrolled = parseAttendanceCount(draft.enrolled);
  const totalPresent = parseAttendanceCount(draft.present);

  if (totalEnrolled === null || totalPresent === null || totalEnrolled <= 0) {
    return null;
  }

  return (totalPresent / totalEnrolled) * 100;
}

export function getTodayData(
  summaries: readonly CampusAttendanceSummaryViewModel[],
  campusId: CampusId,
  today: string,
): readonly CampusAttendanceSummaryViewModel[] {
  return summaries.filter((record) => record.campus_id === campusId && record.date === today);
}

export function getWeekData(
  summaries: readonly CampusAttendanceSummaryViewModel[],
  campusId: CampusId,
  weekStart: string,
  weekEnd: string,
): readonly CampusAttendanceSummaryViewModel[] {
  return summaries.filter(
    (record) => record.campus_id === campusId && record.date >= weekStart && record.date <= weekEnd,
  );
}

export function getWeeklyAverage(
  summaries: readonly CampusAttendanceSummaryViewModel[],
  campusId: CampusId,
  weekStart: string,
  weekEnd: string,
): number | null {
  const weekData = getWeekData(summaries, campusId, weekStart, weekEnd);

  if (weekData.length === 0) {
    return null;
  }

  const avg = weekData.reduce((sum, record) => sum + record.attendance_percentage, 0) / weekData.length;
  return Number(avg.toFixed(2));
}

export function getTodayPercentage(
  summaries: readonly CampusAttendanceSummaryViewModel[],
  campusId: CampusId,
  today: string,
): number | null {
  const todayData = getTodayData(summaries, campusId, today);
  return todayData[0]?.attendance_percentage ?? null;
}

export function buildCampusAttendanceStats(
  campuses: readonly CampusInfo[],
  configs: readonly CampusAttendanceConfigViewModel[],
  summaries: readonly CampusAttendanceSummaryViewModel[],
  today: string,
  weekStart: string,
  weekEnd: string,
): readonly CampusAttendanceStats[] {
  return campuses.map((campus) => {
    const todayPct = getTodayPercentage(summaries, campus.id, today);
    const weekAvg = getWeeklyAverage(summaries, campus.id, weekStart, weekEnd);
    const config = configs.find((item) => item.campus_id === campus.id) ?? null;
    const recentData = summaries.filter((record) => record.campus_id === campus.id).slice(0, 10);
    const todayRecord = getTodayData(summaries, campus.id, today)[0] ?? null;

    return {
      ...campus,
      todayPct,
      weekAvg,
      config,
      recentData,
      todayRecord,
    };
  });
}

export function buildOverallAttendanceStats(
  summaries: readonly CampusAttendanceSummaryViewModel[],
  today: string,
  weekStart: string,
  weekEnd: string,
): CampusAttendanceOverallStats {
  const todayRecords = summaries.filter((record) => record.date === today);
  const todayEnrolled = todayRecords.reduce((sum, record) => sum + record.total_enrolled, 0);
  const todayPresent = todayRecords.reduce((sum, record) => sum + record.total_present, 0);
  const todayPct = todayEnrolled > 0 ? Number(((todayPresent / todayEnrolled) * 100).toFixed(2)) : null;
  const weekRecords = summaries.filter((record) => record.date >= weekStart && record.date <= weekEnd);
  const weekDays = Array.from(new Set(weekRecords.map((record) => record.date)));
  const weekPct = weekDays.length > 0
    ? Number((weekDays.reduce((sum, day) => {
      const dayRecords = weekRecords.filter((record) => record.date === day);
      const dayEnrolled = dayRecords.reduce((daySum, record) => daySum + record.total_enrolled, 0);
      const dayPresent = dayRecords.reduce((daySum, record) => daySum + record.total_present, 0);
      return sum + (dayEnrolled > 0 ? (dayPresent / dayEnrolled) * 100 : 0);
    }, 0) / weekDays.length).toFixed(2))
    : null;

  return {
    todayRecords,
    todayEnrolled,
    todayPresent,
    todayPct,
    weekRecords,
    weekPct,
  };
}

export function buildPrintAttendanceStats(input: CampusAttendancePrintInput) {
  const printEnrolled = input.printTodayRecords.reduce((sum, record) => sum + record.total_enrolled, 0);
  const printPresent = input.printTodayRecords.reduce((sum, record) => sum + record.total_present, 0);
  const todayPct = printEnrolled > 0 ? Number(((printPresent / printEnrolled) * 100).toFixed(2)) : null;
  const weekDays = Array.from(new Set(input.printWeekRecords.map((record) => record.date)));
  const weekPct = weekDays.length > 0
    ? Number((weekDays.reduce((sum, day) => {
      const dayRecords = input.printWeekRecords.filter((record) => record.date === day);
      const dayEnrolled = dayRecords.reduce((daySum, record) => daySum + record.total_enrolled, 0);
      const dayPresent = dayRecords.reduce((daySum, record) => daySum + record.total_present, 0);
      return sum + (dayEnrolled > 0 ? (dayPresent / dayEnrolled) * 100 : 0);
    }, 0) / weekDays.length).toFixed(2))
    : null;

  return {
    todayPct,
    weekPct,
  };
}
