package com.zioinfo.kintex.module.m4;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zioinfo.kintex.module.m4.dto.UtilityQuote;
import com.zioinfo.kintex.module.m4.dto.UtilityQuoteRequest;
import com.zioinfo.kintex.module.m4.mapper.UtilityOrderMapper;
import com.zioinfo.kintex.module.m4.mapper.WiringMapper;
import com.zioinfo.kintex.rules.RuleProperties;
import com.zioinfo.kintex.rules.RuleSetLoader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;

/**
 * M4 유틸리티 자동 견적 계산 단위테스트 — 실제 요율 룰셋(rates-v1.json) 기준.
 * 소비전력 합산·신청용량 올림·분전반(50A/11kW) 산출·회선/급배수/압축공기 라인·합계 정합을 검증한다.
 */
class UtilityQuoteCalcTest {

    private UtilityServiceImpl service;

    @BeforeEach
    void setUp() {
        RuleProperties props = new RuleProperties();
        props.setComplianceRuleset(new ClassPathResource("rulesets/compliance-v1.json"));
        props.setRateRuleset(new ClassPathResource("rulesets/rates-v1.json"));
        RuleSetLoader loader = new RuleSetLoader(props, new ObjectMapper());
        loader.load();
        service = new UtilityServiceImpl(loader, mock(WiringMapper.class),
                mock(UtilityOrderMapper.class), new ObjectMapper());
    }

    @Test
    void quote_sumsPower_boxesCeil_andLineAmounts() {
        // 2대 × 5.0kW = 10kW → requestedKw 10, 분전반 ceil(10/11)=1
        UtilityQuoteRequest req = new UtilityQuoteRequest(
                List.of(new UtilityQuoteRequest.Device("LED 사이니지", 2, 5.0)),
                2,  // network wired lines
                1,  // plumbing outlets
                1); // compressed air outlets
        UtilityQuote q = service.quote(req);

        assertEquals(10.0, q.totalPowerKw(), 1e-9);
        assertEquals(10, q.requestedKw());
        assertEquals(1, q.distributionBox50A());

        // rates-v1.json: perKw 55000, box50A 100000, wired 150000, plumb 150000, air 150000
        long expected = 10L * 55000   // 전기
                + 1L * 100000         // 분전반
                + 2L * 150000         // 유선회선
                + 1L * 150000         // 급배수
                + 1L * 150000;        // 압축공기
        assertEquals(expected, q.total());
        assertEquals("KRW", q.currency());
        assertEquals("rates-v1.0", q.rulesetVersion());
        assertEquals(5, q.lines().size());
    }

    @Test
    void quote_fractionalKw_roundsUpRequestedCapacity() {
        // 3대 × 2.2kW = 6.6kW → requestedKw ceil = 7
        UtilityQuoteRequest req = new UtilityQuoteRequest(
                List.of(new UtilityQuoteRequest.Device("계측장비", 3, 2.2)),
                0, 0, 0);
        UtilityQuote q = service.quote(req);
        assertEquals(7, q.requestedKw());
        assertEquals(1, q.distributionBox50A()); // ceil(7/11)=1
        assertEquals(7L * 55000 + 100000, q.total());
    }

    @Test
    void quote_noDemand_isZeroWithNoLines() {
        UtilityQuoteRequest req = new UtilityQuoteRequest(List.of(), 0, 0, 0);
        UtilityQuote q = service.quote(req);
        assertEquals(0, q.requestedKw());
        assertEquals(0, q.distributionBox50A());
        assertEquals(0L, q.total());
        assertTrue(q.lines().isEmpty());
        assertTrue(q.disclaimer() != null && !q.disclaimer().isBlank()); // 공시가 고지 항상 포함
    }
}
