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

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

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.web.modules.industryservice.domain.BizYakHerdInventory;
import com.ruoyi.web.modules.industryservice.support.YakHerdInventoryExcelParser.ParsedRow;

@DisplayName("YakHerdInventoryExcelExporter")
class YakHerdInventoryExcelExporterTest
{
    private final YakHerdInventoryExcelExporter exporter = new YakHerdInventoryExcelExporter();

    @Test
    @DisplayName("2026样例表无库数据时导出应清空样例存栏数")
    void exportFromSampleWorkbookClearsData() throws Exception
    {
        try (java.io.InputStream sample = getClass().getResourceAsStream("/excel/yak_herd_inventory_2026.xlsx");
                org.apache.poi.ss.usermodel.Workbook sampleWb = org.apache.poi.ss.usermodel.WorkbookFactory.create(sample))
        {
            org.apache.poi.ss.usermodel.Sheet sheet = sampleWb.getSheetAt(0);
            int header = YakHerdInventoryExcelParser.detectHeaderRow(sheet);
            int dataStart = header + 3;
            org.apache.poi.ss.usermodel.DataFormatter fmt = new org.apache.poi.ss.usermodel.DataFormatter();
            org.apache.poi.ss.usermodel.Row firstData = sheet.getRow(dataStart);
            String yakBefore = fmt.formatCellValue(firstData.getCell(YakHerdInventoryExcelParser.COL_YAK_GENDER_TOTAL));
            assertTrue(com.ruoyi.common.utils.StringUtils.isNotEmpty(yakBefore), "样例表首行应有存栏数");

            String[] townNames = {
                "巴青乡", "江绵乡", "岗切乡", "雅安镇", "拉西镇",
                "本塔乡", "杂色镇", "贡日乡", "玛如乡", "阿秀乡"
            };
            java.util.List<SysDept> towns = new java.util.ArrayList<>();
            for (int i = 0; i < townNames.length; i++)
            {
                SysDept d = new SysDept();
                d.setDeptId(100L + i);
                d.setDeptName(townNames[i]);
                d.setOrderNum(13 + i);
                towns.add(d);
            }
            byte[] bytes = exporter.exportWorkbook(sampleWb, 2026, 5, towns, Collections.emptyMap(), null);
            try (org.apache.poi.ss.usermodel.Workbook out = org.apache.poi.ss.usermodel.WorkbookFactory.create(
                    new java.io.ByteArrayInputStream(bytes)))
            {
                java.util.List<ParsedRow> rows = YakHerdInventoryExcelParser.parse(
                        new java.io.ByteArrayInputStream(bytes));
                for (ParsedRow row : rows)
                {
                    assertTrue(row.getYakTotal() == null || row.getYakTotal() == 0,
                            row.getTownName() + " 导出后不应含样例存栏数，实际=" + row.getYakTotal());
                }
            }
        }
    }

    @Test
    @DisplayName("无填报数据时全县乡镇导出均不应含存栏数")
    void exportAllTownsEmptyClearsTemplateSampleData() throws Exception
    {
        String[] townNames = {
            "巴青乡", "江绵乡", "岗切乡", "雅安镇", "拉西镇",
            "本塔乡", "杂色镇", "贡日乡", "玛如乡", "阿秀乡"
        };
        java.util.List<SysDept> towns = new java.util.ArrayList<>();
        for (int i = 0; i < townNames.length; i++)
        {
            SysDept town = new SysDept();
            town.setDeptId(100L + i);
            town.setDeptName(townNames[i]);
            town.setOrderNum(13 + i);
            towns.add(town);
        }

        byte[] bytes = exporter.export(2026, 5, towns, Collections.emptyMap());
        try (java.io.ByteArrayInputStream in = new java.io.ByteArrayInputStream(bytes))
        {
            java.util.List<ParsedRow> rows = YakHerdInventoryExcelParser.parse(in);
            assertEquals(10, rows.size());
            for (ParsedRow row : rows)
            {
                assertTrue(row.getYakTotal() == null || row.getYakTotal() == 0,
                        row.getTownName() + " 不应有存栏数，实际=" + row.getYakTotal());
            }
        }
    }

    @Test
    @DisplayName("按年月导出全县乡镇 Excel")
    void exportByYear() throws Exception
    {
        SysDept town = new SysDept();
        town.setDeptId(101L);
        town.setDeptName("巴青乡");
        town.setOrderNum(13);

        BizYakHerdInventory inv = new BizYakHerdInventory();
        inv.setTownDeptId(101L);
        inv.setTownName("巴青乡");
        inv.setVillageCount(26);
        inv.setHerdsmanHouseholdCount(1605);
        inv.setBreedingBullCount(504);
        inv.setBullCastratedCount(7653);
        inv.setCowYoungCount(2301);
        inv.setCowAdultCount(11129);
        inv.setInsuredYakCount(100);
        inv.setMilkingCowCount(10);
        inv.setFertileCowCount(20);
        inv.setSheepTotal(50);
        YakHerdInventoryValidation.recalculateDerived(inv);

        Map<Long, BizYakHerdInventory> map = new HashMap<>();
        map.put(101L, inv);

        byte[] bytes = exporter.export(2026, 5, Collections.singletonList(town), map);
        assertNotNull(bytes);
        assertTrue(bytes.length > 1000);

        try (java.io.ByteArrayInputStream in = new java.io.ByteArrayInputStream(bytes))
        {
            java.util.List<ParsedRow> rows = YakHerdInventoryExcelParser.parse(in);
            assertTrue(rows.size() >= 1);
            assertTrue(rows.stream().anyMatch(r -> Integer.valueOf(21687).equals(r.getYakTotal())));
            try (org.apache.poi.ss.usermodel.Workbook wb = org.apache.poi.ss.usermodel.WorkbookFactory.create(
                    new java.io.ByteArrayInputStream(bytes)))
            {
                int header = YakHerdInventoryExcelParser.detectHeaderRow(wb.getSheetAt(0));
                org.apache.poi.ss.usermodel.Row dataRow = wb.getSheetAt(0).getRow(header + 3);
                org.apache.poi.ss.usermodel.DataFormatter fmt = new org.apache.poi.ss.usermodel.DataFormatter();
                assertEquals("13430", fmt.formatCellValue(dataRow.getCell(YakHerdInventoryExcelParser.COL_YAK_GENDER_COW)));
                assertEquals("13430", fmt.formatCellValue(dataRow.getCell(YakHerdInventoryExcelParser.COL_COW_SECTION_TOTAL)));
            }
        }
    }

    @Test
    @DisplayName("导出标题使用所选年月，填表时间为当月")
    void exportTitleUsesSelectedYearMonth() throws Exception
    {
        java.time.LocalDate today = java.time.LocalDate.now();
        int exportMonth = today.getMonthValue() == 1 ? 12 : today.getMonthValue() - 1;
        int exportYear = today.getMonthValue() == 1 ? today.getYear() - 1 : today.getYear();
        if (!YakHerdInventoryYearSupport.isAllowedYear(exportYear))
        {
            exportYear = today.getYear();
            exportMonth = Math.max(1, today.getMonthValue() - 1);
        }

        BizYakHerdInventory inv = new BizYakHerdInventory();
        inv.setTownName("雅安镇");
        inv.setVillageName("测试村");
        inv.setVillageDeptId(201L);
        inv.setVillageCount(1);
        inv.setHerdsmanHouseholdCount(1);
        inv.setBreedingBullCount(1);
        inv.setBullCastratedCount(1);
        inv.setCowYoungCount(1);
        inv.setCowAdultCount(1);
        inv.setMilkingCowCount(1);
        inv.setFertileCowCount(1);
        inv.setSheepTotal(1);
        inv.setMilkingSheepCount(0);
        inv.setInsuredYakCount(0);
        YakHerdInventoryValidation.recalculateDerived(inv);

        byte[] bytes = exporter.export(exportYear, exportMonth, Collections.singletonList(inv), "admin");
        try (org.apache.poi.ss.usermodel.Workbook wb = org.apache.poi.ss.usermodel.WorkbookFactory.create(
                new java.io.ByteArrayInputStream(bytes)))
        {
            org.apache.poi.ss.usermodel.DataFormatter fmt = new org.apache.poi.ss.usermodel.DataFormatter();
            String title = fmt.formatCellValue(wb.getSheetAt(0).getRow(0).getCell(0));
            String filler = fmt.formatCellValue(wb.getSheetAt(0).getRow(1).getCell(0));
            assertTrue(title.contains(exportYear + "年"), title);
            assertTrue(title.contains("（" + exportMonth + "月）"), title);
            assertTrue(filler.contains("填表时间：" + today.getYear() + "年" + today.getMonthValue() + "月"), filler);
        }
    }

    @Test
    @DisplayName("导出合计行应保留边框（数据行多于模板样例时）")
    void exportTotalRowKeepsBorders() throws Exception
    {
        java.util.List<BizYakHerdInventory> list = new java.util.ArrayList<>();
        for (int i = 0; i < 3; i++)
        {
            BizYakHerdInventory inv = new BizYakHerdInventory();
            inv.setTownName("雅安镇");
            inv.setVillageName("村" + i);
            inv.setVillageDeptId(200L + i);
            inv.setVillageCount(10);
            inv.setHerdsmanHouseholdCount(10);
            inv.setBreedingBullCount(1);
            inv.setBullCastratedCount(2);
            inv.setCowYoungCount(3);
            inv.setCowAdultCount(4);
            inv.setMilkingCowCount(5);
            inv.setFertileCowCount(6);
            inv.setSheepTotal(7);
            inv.setMilkingSheepCount(1);
            inv.setInsuredYakCount(1);
            YakHerdInventoryValidation.recalculateDerived(inv);
            list.add(inv);
        }

        byte[] bytes = exporter.export(2026, 7, list, "admin");
        try (org.apache.poi.ss.usermodel.Workbook wb = org.apache.poi.ss.usermodel.WorkbookFactory.create(
                new java.io.ByteArrayInputStream(bytes)))
        {
            org.apache.poi.ss.usermodel.Sheet sheet = wb.getSheetAt(0);
            int header = YakHerdInventoryExcelParser.detectHeaderRow(sheet);
            int totalIdx = header + 3 + list.size();
            org.apache.poi.ss.usermodel.Row totalRow = sheet.getRow(totalIdx);
            assertNotNull(totalRow);
            org.apache.poi.ss.usermodel.DataFormatter fmt = new org.apache.poi.ss.usermodel.DataFormatter();
            assertEquals("合计", fmt.formatCellValue(totalRow.getCell(0)));
            for (int col = 0; col <= YakHerdInventoryExcelParser.COL_LAST; col++)
            {
                org.apache.poi.ss.usermodel.Cell cell = totalRow.getCell(col);
                assertNotNull(cell, "合计行列 " + col + " 应存在");
                assertTrue(cell.getCellStyle().getBorderBottom() != org.apache.poi.ss.usermodel.BorderStyle.NONE,
                        "合计行列 " + col + " 应有下边框");
            }
        }
    }

    @Test
    @DisplayName("数据行不应继承模板合计行的合并单元格")
    void exportDataRowsHaveNoMergedTownVillage() throws Exception
    {
        java.util.List<BizYakHerdInventory> list = new java.util.ArrayList<>();
        for (int i = 0; i < 4; i++)
        {
            BizYakHerdInventory inv = new BizYakHerdInventory();
            inv.setTownName("雅安镇");
            inv.setVillageName("测试村" + i);
            inv.setVillageDeptId(300L + i);
            inv.setVillageCount(1);
            inv.setHerdsmanHouseholdCount(1);
            inv.setBreedingBullCount(1);
            inv.setBullCastratedCount(1);
            inv.setCowYoungCount(1);
            inv.setCowAdultCount(1);
            inv.setMilkingCowCount(1);
            inv.setFertileCowCount(1);
            inv.setSheepTotal(1);
            inv.setMilkingSheepCount(0);
            inv.setInsuredYakCount(0);
            YakHerdInventoryValidation.recalculateDerived(inv);
            list.add(inv);
        }

        byte[] bytes = exporter.export(2026, 5, list, "admin");
        try (org.apache.poi.ss.usermodel.Workbook wb = org.apache.poi.ss.usermodel.WorkbookFactory.create(
                new java.io.ByteArrayInputStream(bytes)))
        {
            org.apache.poi.ss.usermodel.Sheet sheet = wb.getSheetAt(0);
            int header = YakHerdInventoryExcelParser.detectHeaderRow(sheet);
            int dataStart = header + 3;
            int totalIdx = dataStart + list.size();
            org.apache.poi.ss.usermodel.DataFormatter fmt = new org.apache.poi.ss.usermodel.DataFormatter();

            for (int r = dataStart; r < totalIdx; r++)
            {
                org.apache.poi.ss.usermodel.Row row = sheet.getRow(r);
                assertNotNull(row);
                assertEquals("雅安镇", fmt.formatCellValue(row.getCell(YakHerdInventoryExcelParser.COL_TOWN)));
                assertTrue(fmt.formatCellValue(row.getCell(YakHerdInventoryExcelParser.COL_VILLAGE_NAME))
                        .startsWith("测试村"));
                for (int i = 0; i < sheet.getNumMergedRegions(); i++)
                {
                    org.apache.poi.ss.util.CellRangeAddress region = sheet.getMergedRegion(i);
                    assertFalse(region.getFirstRow() <= r && region.getLastRow() >= r
                                    && region.getFirstColumn() <= YakHerdInventoryExcelParser.COL_TOWN
                                    && region.getLastColumn() >= YakHerdInventoryExcelParser.COL_TOWN,
                            "数据行 " + r + " 不应合并乡镇/村列");
                }
            }

            boolean totalMerged = false;
            for (int i = 0; i < sheet.getNumMergedRegions(); i++)
            {
                org.apache.poi.ss.util.CellRangeAddress region = sheet.getMergedRegion(i);
                if (region.getFirstRow() == totalIdx && region.getLastRow() == totalIdx
                        && region.getFirstColumn() == 0
                        && region.getLastColumn() == YakHerdInventoryExcelParser.COL_VILLAGE_NAME)
                {
                    totalMerged = true;
                }
            }
            assertTrue(totalMerged, "仅合计行应合并序号~村三列");
        }
    }
}
