package com.ruoyi.web.modules.industryservice.support;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Date;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.industryservice.domain.BizGrassland;

/**
 * ZCZX-CCGL-UT-001～009、016
 */
@DisplayName("GrasslandValidation")
class GrasslandValidationTest
{
    @Test
    @DisplayName("ZCZX-CCGL-UT-001 草场名称长度")
    void ut001_grasslandName()
    {
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateGrasslandName(""));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateGrasslandName(longStr(11)));
        assertDoesNotThrow(() -> GrasslandValidation.validateGrasslandName("草"));
        assertDoesNotThrow(() -> GrasslandValidation.validateGrasslandName(longStr(10)));
    }

    @Test
    @DisplayName("ZCZX-CCGL-UT-002 备注字数")
    void ut002_remark()
    {
        assertDoesNotThrow(() -> GrasslandValidation.validateRemark(null));
        assertDoesNotThrow(() -> GrasslandValidation.validateRemark(""));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateRemark(longStr(101)));
        assertDoesNotThrow(() -> GrasslandValidation.validateRemark(longStr(100)));
    }

    @Test
    @DisplayName("ZCZX-CCGL-UT-003 退化等级枚举（选填）")
    void ut003_degradationLevel()
    {
        assertDoesNotThrow(() -> GrasslandValidation.validateDegradationLevel(null));
        assertDoesNotThrow(() -> GrasslandValidation.validateDegradationLevel(GrasslandRules.DEGRADATION_NONE));
        assertDoesNotThrow(() -> GrasslandValidation.validateDegradationLevel(GrasslandRules.DEGRADATION_EXTREME));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateDegradationLevel(0));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateDegradationLevel(6));
    }

    @Test
    @DisplayName("ZCZX-CCGL-UT-004 利用类型枚举（选填）")
    void ut004_utilizationType()
    {
        assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationType(null));
        assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationType(GrasslandRules.UTILIZATION_BAN));
        assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationType(GrasslandRules.UTILIZATION_YEAR_ROUND));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateUtilizationType(0));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateUtilizationType(4));
    }

    @Test
    @DisplayName("ZCZX-CCGL-UT-005 面积/亩产草量/禁牧与草畜平衡面积")
    void ut005_areaAndYield()
    {
        assertDoesNotThrow(() -> GrasslandValidation.validateAreaMu(new BigDecimal("100.5")));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateAreaMu(BigDecimal.ZERO));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateAreaMu(new BigDecimal("-1")));

        assertDoesNotThrow(() -> GrasslandValidation.validateGrassYieldPerMu(null));
        assertDoesNotThrow(() -> GrasslandValidation.validateGrassYieldPerMu(new BigDecimal("350")));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateGrassYieldPerMu(BigDecimal.ZERO));

        assertDoesNotThrow(() -> GrasslandValidation.validateOptionalPositiveArea(null, "禁牧面积"));
        assertDoesNotThrow(() -> GrasslandValidation.validateOptionalPositiveArea(new BigDecimal("10"), "禁牧面积"));
        assertThrows(ServiceException.class,
                () -> GrasslandValidation.validateOptionalPositiveArea(BigDecimal.ZERO, "禁牧面积"));
        assertThrows(ServiceException.class,
                () -> GrasslandValidation.validateOptionalPositiveArea(new BigDecimal("-1"), "草畜平衡面积"));
    }

    @Test
    @DisplayName("ZCZX-CCGL-UT-006 利用率区间（选填）")
    void ut006_utilizationRate()
    {
        assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationRate(null));
        assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationRate(BigDecimal.ZERO));
        assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationRate(BigDecimal.ONE));
        assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationRate(new BigDecimal("0.65")));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateUtilizationRate(new BigDecimal("-0.1")));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateUtilizationRate(new BigDecimal("1.1")));
    }

    @Test
    @DisplayName("ZCZX-CCGL-UT-007 禁牧日期区间（选填成对）")
    void ut007_grazingBanDates()
    {
        Date start = Date.valueOf("2025-01-01");
        Date end = Date.valueOf("2025-03-31");
        assertDoesNotThrow(() -> GrasslandValidation.validateGrazingBanDates(null, null));
        assertDoesNotThrow(() -> GrasslandValidation.validateGrazingBanDates(start, end));
        assertThrows(ServiceException.class,
                () -> GrasslandValidation.validateGrazingBanDates(Date.valueOf("2025-04-01"), end));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateGrazingBanDates(start, null));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateGrazingBanDates(null, end));
    }

    @Test
    @DisplayName("ZCZX-CCGL-UT-008 轮牧三项整数（选填）")
    void ut008_rotationParams()
    {
        assertDoesNotThrow(() -> GrasslandValidation.validateRotationPlotCount(null));
        assertDoesNotThrow(() -> GrasslandValidation.validateRotationPlotCount(1));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateRotationPlotCount(0));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateRotationGrazingDays(0));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateRotationCycleDays(0));
    }

    @Test
    @DisplayName("ZCZX-CCGL-UT-009 全量保存校验（仅名称+面积必填）")
    void ut009_validateRowForSave()
    {
        assertDoesNotThrow(() -> GrasslandValidation.validateRowForSave(sampleRow()));
        BizGrassland minimal = new BizGrassland();
        minimal.setGrasslandName("最小草场");
        minimal.setAreaMu(new BigDecimal("1"));
        assertDoesNotThrow(() -> GrasslandValidation.validateRowForSave(minimal));
        BizGrassland bad = sampleRow();
        bad.setUtilizationRate(new BigDecimal("2"));
        assertThrows(ServiceException.class, () -> GrasslandValidation.validateRowForSave(bad));
    }

    @Test
    @DisplayName("ZCZX-CCGL-UT-016 列表排序与删除过滤 SQL")
    void ut016_mapperXml() throws Exception
    {
        String path = "src/main/resources/mapper/industryservice/BizGrasslandMapper.xml";
        String xml = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8);
        assertTrue(xml.contains("create_time desc"));
        assertTrue(xml.contains("id desc"));
        assertTrue(xml.contains("del_flag = '0'"));
        assertTrue(xml.contains("del_flag = '2'"));
        assertTrue(xml.contains("grazing_ban_area"));
        assertTrue(xml.contains("grass_balance_area"));
    }

    private static BizGrassland sampleRow()
    {
        BizGrassland r = new BizGrassland();
        r.setGrasslandName("示范草场");
        r.setAreaMu(new BigDecimal("100.5"));
        r.setGrazingBanArea(new BigDecimal("30"));
        r.setGrassBalanceArea(new BigDecimal("70.5"));
        r.setDegradationLevel(GrasslandRules.DEGRADATION_NONE);
        r.setUtilizationType(GrasslandRules.UTILIZATION_ROTATION);
        r.setGrassYieldPerMu(new BigDecimal("350"));
        r.setUtilizationRate(new BigDecimal("0.65"));
        r.setGrazingBanStartDate(Date.valueOf("2025-01-01"));
        r.setGrazingBanEndDate(Date.valueOf("2025-03-31"));
        r.setRotationPlotCount(4);
        r.setRotationGrazingDays(7);
        r.setRotationCycleDays(28);
        return r;
    }

    private static String longStr(int len)
    {
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++)
        {
            sb.append('x');
        }
        return sb.toString();
    }
}
