package org.springblade.modules.martial.service.schedule.generator;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springblade.modules.martial.pojo.entity.MartialCompetition;
import org.springblade.modules.martial.service.schedule.model.TimeSlot;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Unit tests for TimeSlotGenerator
 */
@DisplayName("TimeSlotGenerator Tests")
class TimeSlotGeneratorTest {

    private TimeSlotGenerator generator;

    @BeforeEach
    void setUp() {
        generator = new TimeSlotGenerator();
    }

    @Test
    @DisplayName("Should generate 3 slots per day")
    void shouldGenerate3SlotsPerDay() {
        LocalDate date = LocalDate.of(2026, 1, 15);
        List<TimeSlot> slots = generator.generateDailySlots(date);
        
        assertEquals(3, slots.size());
        assertTrue(slots.get(0).isMorning());
        assertTrue(slots.get(1).isAfternoon());
        assertTrue(slots.get(2).isEvening());
    }

    @Test
    @DisplayName("Should generate correct time slots for single day competition")
    void shouldGenerateSlotsForSingleDay() {
        LocalDateTime start = LocalDateTime.of(2026, 1, 15, 8, 0);
        LocalDateTime end = LocalDateTime.of(2026, 1, 15, 22, 0);
        
        List<TimeSlot> slots = generator.generate(start, end);
        
        assertEquals(3, slots.size());
    }

    @Test
    @DisplayName("Should generate correct time slots for multi-day competition")
    void shouldGenerateSlotsForMultiDay() {
        LocalDateTime start = LocalDateTime.of(2026, 1, 15, 8, 0);
        LocalDateTime end = LocalDateTime.of(2026, 1, 17, 22, 0);
        
        List<TimeSlot> slots = generator.generate(start, end);
        
        assertEquals(9, slots.size()); // 3 days * 3 slots
    }

    @Test
    @DisplayName("Should return empty list when times are null")
    void shouldReturnEmptyWhenTimesNull() {
        List<TimeSlot> slots = generator.generate(null, null);
        assertTrue(slots.isEmpty());
    }

    @Test
    @DisplayName("Should generate from competition entity")
    void shouldGenerateFromCompetition() {
        MartialCompetition competition = new MartialCompetition();
        competition.setCompetitionStartTime(LocalDateTime.of(2026, 1, 15, 8, 0));
        competition.setCompetitionEndTime(LocalDateTime.of(2026, 1, 16, 22, 0));
        
        List<TimeSlot> slots = generator.generate(competition);
        
        assertEquals(6, slots.size()); // 2 days * 3 slots
    }

    @Test
    @DisplayName("Should return empty list when competition is null")
    void shouldReturnEmptyWhenCompetitionNull() {
        List<TimeSlot> slots = generator.generate((MartialCompetition) null);
        assertTrue(slots.isEmpty());
    }

    @Test
    @DisplayName("Should calculate correct total capacity")
    void shouldCalculateTotalCapacity() {
        LocalDateTime start = LocalDateTime.of(2026, 1, 15, 8, 0);
        LocalDateTime end = LocalDateTime.of(2026, 1, 15, 22, 0);
        
        List<TimeSlot> slots = generator.generate(start, end);
        int totalCapacity = generator.calculateTotalCapacity(slots);
        
        // 240 (morning) + 240 (afternoon) + 180 (evening) = 660
        assertEquals(660, totalCapacity);
    }

    @Test
    @DisplayName("Should generate correct slot keys")
    void shouldGenerateCorrectSlotKeys() {
        LocalDate date = LocalDate.of(2026, 1, 15);
        List<TimeSlot> slots = generator.generateDailySlots(date);
        
        assertEquals("2026-01-15_morning", slots.get(0).getSlotKey());
        assertEquals("2026-01-15_afternoon", slots.get(1).getSlotKey());
        assertEquals("2026-01-15_evening", slots.get(2).getSlotKey());
    }

    @Test
    @DisplayName("Morning slot should have correct configuration")
    void morningShouldHaveCorrectConfig() {
        LocalDate date = LocalDate.of(2026, 1, 15);
        List<TimeSlot> slots = generator.generateDailySlots(date);
        TimeSlot morning = slots.get(0);
        
        assertEquals("08:00", morning.getStartTime());
        assertEquals(240, morning.getCapacity());
        assertTrue(morning.isMorning());
        assertFalse(morning.isAfternoon());
        assertFalse(morning.isEvening());
    }

    @Test
    @DisplayName("Afternoon slot should have correct configuration")
    void afternoonShouldHaveCorrectConfig() {
        LocalDate date = LocalDate.of(2026, 1, 15);
        List<TimeSlot> slots = generator.generateDailySlots(date);
        TimeSlot afternoon = slots.get(1);
        
        assertEquals("14:00", afternoon.getStartTime());
        assertEquals(240, afternoon.getCapacity());
        assertFalse(afternoon.isMorning());
        assertTrue(afternoon.isAfternoon());
        assertFalse(afternoon.isEvening());
    }

    @Test
    @DisplayName("Evening slot should have correct configuration")
    void eveningShouldHaveCorrectConfig() {
        LocalDate date = LocalDate.of(2026, 1, 15);
        List<TimeSlot> slots = generator.generateDailySlots(date);
        TimeSlot evening = slots.get(2);
        
        assertEquals("19:00", evening.getStartTime());
        assertEquals(180, evening.getCapacity());
        assertFalse(evening.isMorning());
        assertFalse(evening.isAfternoon());
        assertTrue(evening.isEvening());
    }
}
