package com.ruoyi.web.modules.industryservice.service.impl;

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.industryservice.domain.BizGrassLivestockImbalanceWarning;
import com.ruoyi.web.modules.industryservice.domain.BizLargeLivestockFarmer;
import com.ruoyi.web.modules.industryservice.domain.vo.LargeLivestockFarmerImportResultVo;
import com.ruoyi.web.modules.industryservice.mapper.BizLargeLivestockFarmerMapper;
import com.ruoyi.web.modules.industryservice.service.IBizLargeLivestockFarmerService;
import com.ruoyi.web.modules.industryservice.support.GrassLivestockImbalanceWarningRules;
import com.ruoyi.web.modules.industryservice.support.GrassLivestockImbalanceWarningSyncSupport;
import com.ruoyi.web.modules.industryservice.support.LargeLivestockFarmerDerivedSupport;
import com.ruoyi.web.modules.industryservice.support.LargeLivestockFarmerExcelExporter;
import com.ruoyi.web.modules.industryservice.support.LargeLivestockFarmerExcelParser;
import com.ruoyi.web.modules.industryservice.support.LargeLivestockFarmerExcelParser.ParsedRow;
import com.ruoyi.web.modules.industryservice.support.LargeLivestockFarmerValidation;
import com.ruoyi.web.modules.industryservice.support.ReportDeptDataScopeSupport;
import com.ruoyi.web.modules.industryservice.support.TownDeptSupport;
import com.ruoyi.web.modules.industryservice.support.YakHerdInventoryMonthSupport;
import com.ruoyi.web.modules.industryservice.support.YakHerdInventoryYearSupport;

/**
 * 养殖大户数据填报服务实现。
 * <p>
 * 核心规则：
 * <ul>
 *   <li>唯一键 (年, 月, 村, 企业名称)；手工保存冲突提示「该年该月该村该企业已填报」</li>
 *   <li>导入按唯一键 upsert；任一行失败整批回滚</li>
 *   <li>草畜失衡写入独立表 {@code biz_grass_livestock_imbalance_warning}
 *       （{@code data_source=large_livestock_farmer}，{@code source_key=LLF-{id}}）；
 *       恢复平衡或删除记录时清除对应预警</li>
 * </ul>
 * </p>
 */
@Service
public class BizLargeLivestockFarmerServiceImpl implements IBizLargeLivestockFarmerService
{
    @Autowired
    private BizLargeLivestockFarmerMapper bizLargeLivestockFarmerMapper;

    @Autowired
    private GrassLivestockImbalanceWarningSyncSupport grassLivestockImbalanceWarningSyncSupport;

    @Autowired
    private TownDeptSupport townDeptSupport;

    @Autowired
    private LargeLivestockFarmerExcelExporter largeLivestockFarmerExcelExporter;

    @Override
    public BizLargeLivestockFarmer selectBizLargeLivestockFarmerById(Long id)
    {
        return bizLargeLivestockFarmerMapper.selectBizLargeLivestockFarmerById(id);
    }

    @Override
    public List<BizLargeLivestockFarmer> selectBizLargeLivestockFarmerList(BizLargeLivestockFarmer query)
    {
        ReportDeptDataScopeSupport.apply(query, "r");
        return bizLargeLivestockFarmerMapper.selectBizLargeLivestockFarmerList(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertBizLargeLivestockFarmer(BizLargeLivestockFarmer row)
    {
        LargeLivestockFarmerValidation.validateRowForSave(row, townDeptSupport);
        assertUnique(row.getStatYear(), row.getStatMonth(), row.getVillageDeptId(), row.getEnterpriseName(), null);
        int rows = bizLargeLivestockFarmerMapper.insertBizLargeLivestockFarmer(row);
        syncGrassImbalanceWarning(row);
        return rows;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateBizLargeLivestockFarmer(BizLargeLivestockFarmer row)
    {
        if (row.getId() == null)
        {
            throw new ServiceException("主键不能为空");
        }
        LargeLivestockFarmerValidation.validateRowForSave(row, townDeptSupport);
        requireExistingRow(row.getId());
        assertUnique(row.getStatYear(), row.getStatMonth(), row.getVillageDeptId(), row.getEnterpriseName(),
                row.getId());
        int rows = bizLargeLivestockFarmerMapper.updateBizLargeLivestockFarmer(row);
        syncGrassImbalanceWarning(row);
        return rows;
    }

    /**
     * 物理删除填报记录，并批量清除关联草畜失衡预警（source_key = LLF-{id}）。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteBizLargeLivestockFarmerByIds(Long[] ids, String updateBy)
    {
        if (ids == null || ids.length == 0)
        {
            return 0;
        }
        List<Long> cleaned = new ArrayList<>();
        for (Long id : ids)
        {
            if (id != null)
            {
                cleaned.add(id);
            }
        }
        if (cleaned.isEmpty())
        {
            return 0;
        }
        Long[] ranchIds = cleaned.toArray(new Long[0]);
        List<String> sourceKeys = new ArrayList<>();
        for (Long ranchId : ranchIds)
        {
            sourceKeys.add(GrassLivestockImbalanceWarningRules.largeLivestockFarmerSourceKey(ranchId));
        }
        grassLivestockImbalanceWarningSyncSupport.deleteBySourceKeys(sourceKeys);
        return bizLargeLivestockFarmerMapper.deleteBizLargeLivestockFarmerByIds(ranchIds);
    }

    /**
     * Excel 导入：按 (年, 月, 村, 企业名称) 存在则更新、不存在则插入。
     * <ol>
     *   <li>校验文件与年月</li>
     *   <li>解析行 → 乡镇/村名映射 dept → 业务校验 → 批内唯一键去重</li>
     *   <li>任一行失败则抛异常，事务回滚，整批不写</li>
     *   <li>成功后逐条 upsert，并同步草畜失衡预警</li>
     * </ol>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LargeLivestockFarmerImportResultVo importData(MultipartFile file, Integer statYear, Integer statMonth,
            String username)
    {
        if (file == null || file.isEmpty())
        {
            throw new ServiceException("请上传 Excel 文件");
        }
        String filename = file.getOriginalFilename();
        if (filename == null || !filename.toLowerCase().endsWith(".xlsx"))
        {
            throw new ServiceException("仅支持 .xlsx 格式");
        }
        YakHerdInventoryMonthSupport.validateStatPeriod(statYear, statMonth);
        LargeLivestockFarmerImportResultVo result = new LargeLivestockFarmerImportResultVo();
        List<ParsedRow> parsedRows;
        try
        {
            parsedRows = LargeLivestockFarmerExcelParser.parse(file.getInputStream());
        }
        catch (ServiceException ex)
        {
            throw ex;
        }
        catch (Exception ex)
        {
            throw new ServiceException("读取 Excel 失败：" + ex.getMessage());
        }

        List<BizLargeLivestockFarmer> toSave = new ArrayList<>();
        java.util.Set<String> batchKeys = new java.util.HashSet<>();
        for (ParsedRow parsed : parsedRows)
        {
            try
            {
                SysDept town = townDeptSupport.resolveTownByName(parsed.getTownName());
                if (town == null)
                {
                    result.addFail("第" + parsed.getExcelRowNum() + "行[" + parsed.getTownName() + "]: 乡镇未识别");
                    continue;
                }
                if (StringUtils.isEmpty(parsed.getVillageName()))
                {
                    result.addFail("第" + parsed.getExcelRowNum() + "行[" + parsed.getTownName() + "]: 所属村不能为空");
                    continue;
                }
                SysDept village = townDeptSupport.resolveVillageByTownAndName(town.getDeptId(), parsed.getVillageName());
                if (village == null)
                {
                    result.addFail("第" + parsed.getExcelRowNum() + "行[" + parsed.getTownName() + "/"
                            + parsed.getVillageName() + "]: 村未识别");
                    continue;
                }
                BizLargeLivestockFarmer row = LargeLivestockFarmerExcelParser.toEntity(parsed, statYear, statMonth, town.getDeptId(),
                        town.getDeptName(), village.getDeptId(), village.getDeptName());
                LargeLivestockFarmerValidation.validateRowForSave(row, townDeptSupport);
                String batchKey = row.getStatYear() + "|" + row.getStatMonth() + "|" + row.getVillageDeptId() + "|"
                        + row.getEnterpriseName();
                if (!batchKeys.add(batchKey))
                {
                    result.addFail("第" + parsed.getExcelRowNum() + "行[" + row.getTownName() + "/"
                            + row.getVillageName() + "/" + row.getEnterpriseName() + "]: 文件内存在重复唯一键");
                    continue;
                }
                toSave.add(row);
            }
            catch (ServiceException ex)
            {
                result.addFail("第" + parsed.getExcelRowNum() + "行[" + parsed.getTownName() + "/"
                        + parsed.getVillageName() + "/" + parsed.getEnterpriseName() + "]: " + ex.getMessage());
            }
        }

        if (result.getFailCount() > 0)
        {
            throw new ServiceException("导入失败，未写入数据：" + String.join("；", result.getFailMessages()));
        }
        if (toSave.isEmpty())
        {
            throw new ServiceException("未解析到有效数据行");
        }

        for (BizLargeLivestockFarmer row : toSave)
        {
            BizLargeLivestockFarmer existing = bizLargeLivestockFarmerMapper.selectByUnique(row.getStatYear(), row.getStatMonth(),
                    row.getVillageDeptId(), row.getEnterpriseName());
            if (existing != null)
            {
                row.setId(existing.getId());
                row.setUpdateBy(username);
                bizLargeLivestockFarmerMapper.updateBizLargeLivestockFarmer(row);
                result.setUpdateCount(result.getUpdateCount() + 1);
            }
            else
            {
                row.setCreateBy(username);
                bizLargeLivestockFarmerMapper.insertBizLargeLivestockFarmer(row);
                result.setInsertCount(result.getInsertCount() + 1);
            }
            syncGrassImbalanceWarning(row);
        }
        return result;
    }

    @Override
    public List<Integer> listYearOptions()
    {
        return YakHerdInventoryYearSupport.resolveYearOptions();
    }

    @Override
    public List<Integer> listMonthOptions()
    {
        return YakHerdInventoryMonthSupport.resolveMonthOptions();
    }

    @Override
    public List<java.util.Map<String, Object>> listTownOptions()
    {
        return townDeptSupport.toOptionList();
    }

    @Override
    public List<com.ruoyi.common.core.domain.TreeSelect> listVillageTree()
    {
        return townDeptSupport.buildVillageTree();
    }

    @Override
    public byte[] exportByYearMonth(Integer statYear, Integer statMonth, Long townDeptId)
    {
        return exportByYearMonth(statYear, statMonth, townDeptId, null);
    }

    /**
     * 按年月导出。先校验年月与可选乡镇，再按条件查库，基于同一导入模板填充行数据（无合计行）。
     *
     * @param townDeptId 为空表示导出该月全部乡镇
     * @param fillerName 写入模板「填表人」；可空
     */
    @Override
    public byte[] exportByYearMonth(Integer statYear, Integer statMonth, Long townDeptId, String fillerName)
    {
        YakHerdInventoryMonthSupport.validateStatPeriod(statYear, statMonth);
        if (townDeptId != null && townDeptSupport.requireReportTown(townDeptId) == null)
        {
            throw new ServiceException("导出乡镇不合法");
        }
        BizLargeLivestockFarmer query = new BizLargeLivestockFarmer();
        query.setStatYear(statYear);
        query.setStatMonth(statMonth);
        query.setTownDeptId(townDeptId);
        ReportDeptDataScopeSupport.apply(query, "r");
        List<BizLargeLivestockFarmer> list = bizLargeLivestockFarmerMapper.selectBizLargeLivestockFarmerList(query);
        return largeLivestockFarmerExcelExporter.export(statYear, statMonth, list, fillerName);
    }

    /**
     * 同步草畜失衡预警到 {@code biz_grass_livestock_imbalance_warning}。
     * <ul>
     *   <li>失衡：插入或更新；主体名=企业名称</li>
     *   <li>已平衡或无法判断：删除 source_key=LLF-{id}</li>
     * </ul>
     */
    private void syncGrassImbalanceWarning(BizLargeLivestockFarmer row)
    {
        if (row == null || row.getId() == null)
        {
            return;
        }
        BizGrassLivestockImbalanceWarning warning = new BizGrassLivestockImbalanceWarning();
        warning.setSourceKey(GrassLivestockImbalanceWarningRules.largeLivestockFarmerSourceKey(row.getId()));
        warning.setDataSource(GrassLivestockImbalanceWarningRules.DATA_SOURCE_LARGE_LIVESTOCK_FARMER);
        warning.setSourceRecordId(row.getId());
        warning.setStatYear(row.getStatYear());
        warning.setStatMonth(row.getStatMonth());
        warning.setTownDeptId(row.getTownDeptId());
        warning.setTownName(row.getTownName());
        warning.setVillageDeptId(row.getVillageDeptId());
        warning.setVillageName(row.getVillageName());
        warning.setSubjectName(row.getEnterpriseName());
        warning.setApprovedCarryingCapacity(row.getApprovedCarryingCapacity());
        warning.setYearEndStockSheepUnit(row.getYearEndStockSheepUnit());
        warning.setAlertMessage(GrassLivestockImbalanceWarningSyncSupport.buildMessage(row.getStatYear(),
                row.getStatMonth(), row.getTownName(), row.getVillageName(), row.getEnterpriseName(),
                row.getApprovedCarryingCapacity(), row.getYearEndStockSheepUnit()));
        grassLivestockImbalanceWarningSyncSupport.sync(LargeLivestockFarmerDerivedSupport.isImbalanced(row), warning);
    }

    private void assertUnique(Integer statYear, Integer statMonth, Long villageDeptId, String enterpriseName,
            Long excludeId)
    {
        if (bizLargeLivestockFarmerMapper.countByUniqueExcludeId(statYear, statMonth, villageDeptId, enterpriseName,
                excludeId) > 0)
        {
            throw new ServiceException("该年该月该村该企业已填报");
        }
    }

    private BizLargeLivestockFarmer requireExistingRow(Long id)
    {
        BizLargeLivestockFarmer row = bizLargeLivestockFarmerMapper.selectBizLargeLivestockFarmerById(id);
        if (row == null)
        {
            throw new ServiceException("记录不存在");
        }
        return row;
    }
}
