package com.njcn.rdms.module.project.service.project;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 工时周聚合的纯函数支撑:周一归一 + 按段均摊。
 * 口径(2026-07-14 更新):工时按段填报无逐日明细,均摊分母 = 段内工作日(周一~周五)数;
 * 周六/周日不参与工作日段均摊;周末单天工时保留在当天展示;份额 scale=4,最终展示由调用方聚合后 setScale(2)。
 */
final class MyWorklogWeekSupport {

    private MyWorklogWeekSupport() {
    }

    /** 任意日期归一到所在 ISO 周的周一(weekStart 入参容错,不强制前端必须传周一)。 */
    static LocalDate normalizeToMonday(LocalDate date) {
        return date.with(DayOfWeek.MONDAY);
    }

    /**
     * 把一笔按段填报的工时摊到所选周的工作日。
     * 返回 [weekMonday, weekMonday+6] 内各自然日的份额(scale=4);无份额的日不出现在 map。
     *
     * <p>前置条件:weekMonday 必须已归一到 ISO 周的周一(调用方先调 {@link #normalizeToMonday})。
     * 方法内不做防御归一,以便在调用方传入非周一时尽早暴露 bug。
     */
    static Map<LocalDate, BigDecimal> apportionToWeek(LocalDate segStart, LocalDate segEnd,
                                                      BigDecimal hours, LocalDate weekMonday) {
        Map<LocalDate, BigDecimal> result = new LinkedHashMap<>();
        if (segStart == null || segEnd == null || hours == null || segStart.isAfter(segEnd)) {
            return result;
        }
        LocalDate weekSunday = weekMonday.plusDays(6);
        List<LocalDate> workdays = segStart.datesUntil(segEnd.plusDays(1))
                .filter(d -> d.getDayOfWeek().getValue() <= 5)
                .toList();
        if (!workdays.isEmpty()) {
            BigDecimal share = hours.divide(BigDecimal.valueOf(workdays.size()), 4, RoundingMode.HALF_UP);
            for (LocalDate d : workdays) {
                if (!d.isBefore(weekMonday) && !d.isAfter(weekSunday)) {
                    result.put(d, share);
                }
            }
            return result;
        }

        List<LocalDate> weekendDays = segStart.datesUntil(segEnd.plusDays(1))
                .filter(d -> d.getDayOfWeek().getValue() > 5)
                .filter(d -> !d.isBefore(weekMonday) && !d.isAfter(weekSunday))
                .toList();
        if (weekendDays.isEmpty()) {
            return result;
        }
        BigDecimal share = hours.divide(BigDecimal.valueOf(weekendDays.size()), 4, RoundingMode.HALF_UP);
        for (LocalDate d : weekendDays) {
            result.put(d, share);
        }
        return result;
    }

}
