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

import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class MyWorklogWeekSupportTest {

    /** 2026-06-08 是周一。 */
    private static final LocalDate MONDAY = LocalDate.of(2026, 6, 8);

    @Test
    void normalizeToMonday_anyDayOfWeek() {
        assertEquals(MONDAY, MyWorklogWeekSupport.normalizeToMonday(LocalDate.of(2026, 6, 10))); // 周三
        assertEquals(MONDAY, MyWorklogWeekSupport.normalizeToMonday(LocalDate.of(2026, 6, 14))); // 周日
        assertEquals(MONDAY, MyWorklogWeekSupport.normalizeToMonday(MONDAY));
    }

    @Test
    void apportion_singleDay() {
        // 单天段(周三 8h)→ 全额落周三
        Map<LocalDate, BigDecimal> r = MyWorklogWeekSupport.apportionToWeek(
                LocalDate.of(2026, 6, 10), LocalDate.of(2026, 6, 10), new BigDecimal("8"), MONDAY);
        assertEquals(1, r.size());
        assertEquals(0, new BigDecimal("8").compareTo(r.get(LocalDate.of(2026, 6, 10))));
    }

    @Test
    void apportion_multiDayWithinWeek() {
        // 周一~周三 12h → 每天 4h
        Map<LocalDate, BigDecimal> r = MyWorklogWeekSupport.apportionToWeek(
                MONDAY, LocalDate.of(2026, 6, 10), new BigDecimal("12"), MONDAY);
        assertEquals(3, r.size());
        assertEquals(0, new BigDecimal("4").compareTo(r.get(MONDAY)));
        assertEquals(0, new BigDecimal("4").compareTo(r.get(LocalDate.of(2026, 6, 10))));
    }

    @Test
    void apportion_spanningWeekend_workdaysOnly() {
        // 周五(6-12)~下周一(6-15) 10h:工作日只有周五+下周一,各 5h;本周(6-8 起)只收周五份额
        Map<LocalDate, BigDecimal> r = MyWorklogWeekSupport.apportionToWeek(
                LocalDate.of(2026, 6, 12), LocalDate.of(2026, 6, 15), new BigDecimal("10"), MONDAY);
        assertEquals(1, r.size());
        assertEquals(0, new BigDecimal("5").compareTo(r.get(LocalDate.of(2026, 6, 12))));
    }

    @Test
    void apportion_crossWeekSegment_nextWeekView() {
        // 同一段(6-12 ~ 6-15)从下周视角(weekMonday=6-15)看:只收下周一 5h
        LocalDate nextMonday = LocalDate.of(2026, 6, 15);
        Map<LocalDate, BigDecimal> r = MyWorklogWeekSupport.apportionToWeek(
                LocalDate.of(2026, 6, 12), nextMonday, new BigDecimal("10"), nextMonday);
        assertEquals(1, r.size());
        assertEquals(0, new BigDecimal("5").compareTo(r.get(nextMonday)));
    }

    @Test
    void apportion_pureWeekendSegment_fallbackToFriday() {
        // 纯周末段(周六 6-13 ~ 周日 6-14)3h → 全额兜底归周五 6-12
        Map<LocalDate, BigDecimal> r = MyWorklogWeekSupport.apportionToWeek(
                LocalDate.of(2026, 6, 13), LocalDate.of(2026, 6, 14), new BigDecimal("3"), MONDAY);
        assertEquals(1, r.size());
        assertEquals(0, new BigDecimal("3").compareTo(r.get(LocalDate.of(2026, 6, 12))));
    }

    @Test
    void apportion_segmentOutsideWeek_empty() {
        // 上上周的段,与所选周无交集 → 空
        Map<LocalDate, BigDecimal> r = MyWorklogWeekSupport.apportionToWeek(
                LocalDate.of(2026, 5, 25), LocalDate.of(2026, 5, 27), new BigDecimal("8"), MONDAY);
        assertTrue(r.isEmpty());
    }

    @Test
    void apportion_roundingScale4() {
        // 10h 摊 3 个工作日 → 每天 3.3333(scale=4)
        Map<LocalDate, BigDecimal> r = MyWorklogWeekSupport.apportionToWeek(
                MONDAY, LocalDate.of(2026, 6, 10), new BigDecimal("10"), MONDAY);
        assertEquals(0, new BigDecimal("3.3333").compareTo(r.get(MONDAY)));
    }

    @Test
    void apportion_pureWeekendSegment_nextWeekView_empty() {
        // 纯周末段(6-13 周六 ~ 6-14 周日)从下一周视角(weekMonday=6-15)查:
        // 兜底周五 6-12 不在 [6-15, 6-19] 范围内 → 返回空 map
        LocalDate nextMonday = LocalDate.of(2026, 6, 15);
        Map<LocalDate, BigDecimal> r = MyWorklogWeekSupport.apportionToWeek(
                LocalDate.of(2026, 6, 13), LocalDate.of(2026, 6, 14), new BigDecimal("3"), nextMonday);
        assertTrue(r.isEmpty());
    }

    @Test
    void apportion_singleWeekendDay_fallbackToFriday() {
        // 单个周末日段(segStart==segEnd==6-13 周六,2h,weekMonday=6-8)→ 全额归周五 6-12
        Map<LocalDate, BigDecimal> r = MyWorklogWeekSupport.apportionToWeek(
                LocalDate.of(2026, 6, 13), LocalDate.of(2026, 6, 13), new BigDecimal("2"), MONDAY);
        assertEquals(1, r.size());
        assertEquals(0, new BigDecimal("2").compareTo(r.get(LocalDate.of(2026, 6, 12))));
    }

    @Test
    void apportion_invalidParams_empty() {
        // null hours → 空 map
        assertTrue(MyWorklogWeekSupport.apportionToWeek(MONDAY, MONDAY, null, MONDAY).isEmpty());
        // segStart 晚于 segEnd → 空 map
        assertTrue(MyWorklogWeekSupport.apportionToWeek(
                LocalDate.of(2026, 6, 10), LocalDate.of(2026, 6, 9), new BigDecimal("8"), MONDAY).isEmpty());
    }

}
