import { HolidayService } from "src/time-and-attendance/domains/services/holiday.service";
import { OvertimeService } from "src/time-and-attendance/domains/services/overtime.service";
import { CsvRow, InternalCsvRow } from "src/time-and-attendance/exports/export-csv-options.dto";

const REGULAR = 'G1';
const OVERTIME = 'G43';

export const consolidateRowHoursAndAmountByType = (rows: InternalCsvRow[]): InternalCsvRow[] => {
    const map = new Map<string, InternalCsvRow>();

    for (const row of rows) {
        const key = `${row.timesheet_id}|${row.bank_code}|${row.week_number}`;
        if (!map.has(key)) {
            map.set(key, { ...row });
        } else {
            const existing = map.get(key)!;
            existing.quantity_hours = (existing.quantity_hours ?? 0) + (row.quantity_hours ?? 0);
            existing.amount = (existing.amount ?? 0) + (row.amount ?? 0);
        }
    }
    return Array.from(map.values());
}

export const applyHolidayRequalifications = async (
    rows: InternalCsvRow[],
    holiday_service: HolidayService,
): Promise<InternalCsvRow[]> => {
    const result: InternalCsvRow[] = [];

    for (const row of rows) {
        if (row.bank_code !== 'G104') {
            result.push(row);
            continue;
        }
        if (!row.holiday_date || !row.email) {
            result.push(row);
            continue;
        }
        
        const calculated = await holiday_service.calculateHolidayPay(row.email, new Date(row.holiday_date), 1);
        if (!calculated.success) {
            result.push({ ...row, quantity_hours: 0 });
            continue;
        }

        result.push({ ...row, quantity_hours: calculated.data });
    }
    return result;
}

export const applyOvertimeRequalifications = async (
    consolidated_rows: InternalCsvRow[],
    overtime_service: OvertimeService,
): Promise<CsvRow[]> => {
    const result: InternalCsvRow[] = [];
    //grouped by timesheet and week number
    const grouped_rows = new Map<string, InternalCsvRow[]>();

    for (const row of consolidated_rows) {
        const key = `${row.timesheet_id}|${row.week_number}`;
        if (!grouped_rows.has(key)) {
            grouped_rows.set(key, []);
        }
        grouped_rows.get(key)!.push({ ...row });
    }

    for (const [, rows] of grouped_rows) {
        //serves only to get the right timesheet_id and a date to find the "week_start of the getWeekOvertimeSummary"
        const representative = rows[0];
        const summary = await overtime_service.getWeekOvertimeSummary(representative.timesheet_id, representative.shift_date);
        if (!summary.success || summary.data.total_overtime <= 0) {
            result.push(...rows);
            continue;
        }

        const overtime_hours = summary.data.total_overtime;

        const regular_hours = rows.find(r => r.bank_code === REGULAR);
        if (!regular_hours || !regular_hours.quantity_hours) {
            result.push(...rows);
            continue;
        }

        const deducted = Math.min(overtime_hours, regular_hours.quantity_hours);

        for (const row of rows) {
            if (row === regular_hours) {
                const remaining = regular_hours.quantity_hours - deducted;
                if (remaining > 0) {
                    result.push({ ...regular_hours, quantity_hours: remaining });
                }
            } else {
                result.push(row);
            }
        }

        result.push({
            ...regular_hours,
            bank_code: OVERTIME,
            quantity_hours: deducted,
        });
    }

    // return consolidateRowHoursAndAmountByType(result);
    return result;
}

export const resolveCompanyCodes = (companies: { targo: boolean; solucom: boolean; }): number[] => {
    const out: number[] = [];
    if (companies.targo) {
        const code_no = 271583;
        out.push(code_no);
    }
    if (companies.solucom) {
        const code_no = 271585;
        out.push(code_no);
    }
    return out;
}

export const computeWeekNumber = (start: Date, date: Date): number => {
    const dayMS = 86400000;
    const days = Math.floor((toUTC(date).getTime() - toUTC(start).getTime()) / dayMS);
    return Math.floor(days / 7) + 1;
}

export const toUTC = (date: Date) => {
    return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
}

export const formatDate = (d: Date): string => {
    return d.toISOString().split('T')[0];
}