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-06-12 与用户确认):工时按段填报无逐日明细,均摊分母 = 段内工作日(周一~周五)数;
 * 纯周末段全额兜底归段结束日前最近的工作日;份额 scale=4,最终展示由调用方聚合后 setScale(2)。
 */
final class MyWorklogWeekSupport {

    private MyWorklogWeekSupport() {
    }

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

    /**
     * 把一笔按段填报的工时摊到所选周的工作日。
     * 返回 [weekMonday, weekMonday+4] 内各工作日的份额(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 weekFriday = weekMonday.plusDays(4);
        List<LocalDate> workdays = segStart.datesUntil(segEnd.plusDays(1))
                .filter(d -> d.getDayOfWeek().getValue() <= 5)
                .toList();
        if (workdays.isEmpty()) {
            // 纯周末段:全额归段结束日前最近的工作日(周六/周日 → 周五)
            LocalDate fallback = segEnd;
            while (fallback.getDayOfWeek().getValue() > 5) {
                fallback = fallback.minusDays(1);
            }
            if (!fallback.isBefore(weekMonday) && !fallback.isAfter(weekFriday)) {
                result.put(fallback, hours.setScale(4, RoundingMode.HALF_UP));
            }
            return result;
        }
        BigDecimal share = hours.divide(BigDecimal.valueOf(workdays.size()), 4, RoundingMode.HALF_UP);
        for (LocalDate d : workdays) {
            if (!d.isBefore(weekMonday) && !d.isAfter(weekFriday)) {
                result.put(d, share);
            }
        }
        return result;
    }

}
