package com.zioinfo.kintex.analytics;

import com.zioinfo.kintex.analytics.dto.AnalyticsDto;
import com.zioinfo.kintex.analytics.dto.AnalyticsOverviewDto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
 * 경영분석 서비스 단위테스트 — 매출=면적×요율 산출, 억 단위 표기·등급, exhibitor 관점 pnl 제외.
 */
class AnalyticsServiceTest {

    private AnalyticsMapper mapper;
    private AnalyticsService service;

    @BeforeEach
    void setUp() {
        mapper = mock(AnalyticsMapper.class);
        service = new AnalyticsService(mapper);
    }

    @Test
    void computesRentalRevenueFromAreaAndRate() {
        when(mapper.findRentalRatePerM2()).thenReturn(2250.0);
        Map<String, Object> ac = new HashMap<>();
        ac.put("salesArea", 100000.0); // 100,000 ㎡
        ac.put("boothCount", 486);
        when(mapper.findAreaAndCount("e1")).thenReturn(ac);
        when(mapper.findUtilityRevenue("e1")).thenReturn(0.0);
        when(mapper.findMonthlyTrend("e1", 0)).thenReturn(List.of());

        AnalyticsDto dto = service.getAnalytics("e1", "operator", "event");

        // 100,000 * 2250 = 225,000,000 → "₩2.25억".
        AnalyticsDto.Kpi rental = dto.kpis().stream()
                .filter(k -> "임대 매출".equals(k.label())).findFirst().orElseThrow();
        assertEquals("₩2.25억", rental.value());

        // operator 관점 → 부스 임대 pnl 존재, grade B(1억~10억).
        AnalyticsDto.PnlRow pnl = dto.pnl().stream()
                .filter(p -> "부스 임대".equals(p.item())).findFirst().orElseThrow();
        assertEquals(225_000_000L, pnl.amount());
        assertEquals("B", pnl.grade());
    }

    @Test
    void exhibitorPerspectiveOmitsPnl() {
        when(mapper.findRentalRatePerM2()).thenReturn(2250.0);
        when(mapper.findAreaAndCount("e1")).thenReturn(new HashMap<>());
        when(mapper.findUtilityRevenue("e1")).thenReturn(0.0);
        when(mapper.findMonthlyTrend("e1", 90)).thenReturn(List.of());

        AnalyticsDto dto = service.getAnalytics("e1", "exhibitor", "d90");

        assertTrue(dto.pnl().isEmpty());
        assertTrue(dto.sectors().isEmpty());
        assertTrue(dto.exhibitorPerf().isEmpty());
    }

    @Test
    void overviewComputesRetentionOccupancyAndForecast() {
        // 행사 횡단 집계는 테넌트 스코프(currentTenantId 기본 'kintex') — 매처는 테넌트 무관 검증.
        when(mapper.findRentalRatePerM2()).thenReturn(2000.0);
        when(mapper.countHalls(anyString())).thenReturn(10L);
        when(mapper.countEvents(anyString())).thenReturn(1098L);
        when(mapper.findUtilityRevenueByEvent(anyString())).thenReturn(List.of());

        Map<String, Object> ev = new HashMap<>();
        ev.put("eventId", "e1");
        ev.put("eventName", "스마트팩토리");
        ev.put("areaM2", 50000.0);
        ev.put("boothCount", 300L);
        when(mapper.findEventAreaRanking(anyString(), eq(8))).thenReturn(List.of(ev));

        Map<String, Object> occ = new HashMap<>();
        occ.put("period", "2026-02"); // 28일
        occ.put("bookedDays", 56L);   // 56 / (10*28)=20%
        when(mapper.findMonthlyEventDays(anyString(), eq(60))).thenReturn(List.of(occ));

        Map<String, Object> retSum = new HashMap<>();
        retSum.put("totalCompanies", 10L);
        retSum.put("returningCompanies", 4L); // 40%
        when(mapper.findRetentionSummary(anyString())).thenReturn(retSum);
        when(mapper.findRetentionByYear(anyString())).thenReturn(List.of());

        // 연 3건씩 증가하는 완벽한 선형 → 다음해 투영 = 마지막+3.
        Map<String, Object> y1 = new HashMap<>();
        y1.put("yr", 2024); y1.put("eventCount", 100L);
        Map<String, Object> y2 = new HashMap<>();
        y2.put("yr", 2025); y2.put("eventCount", 103L);
        Map<String, Object> y3 = new HashMap<>();
        y3.put("yr", 2026); y3.put("eventCount", 106L);
        when(mapper.findYearlyEventCounts(anyString())).thenReturn(List.of(y1, y2, y3));

        AnalyticsOverviewDto dto = service.getOverview(5);

        assertEquals(1, dto.eventComparison().size());
        assertEquals(100_000_000L, dto.eventComparison().get(0).revenue()); // 50000*2000
        assertEquals(20.0, dto.hallOccupancy().get(0).occupancyPercent());
        assertEquals(40.0, dto.retention().retentionPercent());
        assertEquals(2, dto.forecast().projection().size());
        assertEquals(109.0, dto.forecast().projection().get(0).value()); // 106+3
        assertTrue(dto.forecast().projection().get(0).projected());
        assertFalse(dto.forecast().history().isEmpty());
    }
}
