package com.smppw.modaq.application.components.report.parser.pdf;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import com.smppw.modaq.application.components.ReportParseUtils;
import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
import com.smppw.modaq.domain.dto.report.*;
import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
import org.springframework.stereotype.Component;
import technology.tabula.Table;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * @author wangzaijun
 * @date 2024/10/10 17:34
 * @description 年报解析逻辑:基本信息被拆分为多个表格，财务报表未解析
 */
@Component(ReportParserConstant.PARSER_PDF_ANNUALLY)
public class PDAnnuallyReportParser extends PDQuarterlyReportParser<AnnuallyReportData> {
    private List<Table> fundInfoTables;

    public PDAnnuallyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
        super(fieldMappingMapper);
    }

    @Override
    public String getParser() {
        return ReportParserConstant.PARSER_PDF_ANNUALLY;
    }

    @Override
    protected void init() {
        super.init();
        this.fundInfoTables = ListUtil.list(true);
    }

    @Override
    protected void initTableInfo(List<Table> tables) {
        Map<Integer, List<Table>> spanningPageFinancialIndicatorsTableMap = MapUtil.newHashMap(8, true);
        Map<Integer, List<Table>> spanningPageShareChangeTableMap = MapUtil.newHashMap(8, true);
        int fi = 0;
        int sci = 0;
        for (Table table : tables) {
            int colCount = table.getColCount();
            List<String> texts = this.getTableColTexts(table, 0);
            // 用表格的第一列的数据判断是否主要财务指标数据
            if (CollUtil.containsAny(texts, ReportParseUtils.FINANCIAL_INDICATORS_COLUMN_NAMES)) {
                this.splitTables(table, 10, fi, this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
                continue;
            }
            if (colCount == 2) {
                // 用表格的第一列的数据判断是否份额变动记录
                if (CollUtil.containsAny(texts, ReportParseUtils.SHARE_CHANGE_COLUMN_NAMES)) {
                    this.splitTables(table, 5, sci, this.shareChangeTables, spanningPageShareChangeTableMap);
                } else if (CollUtil.containsAny(texts, ReportParseUtils.FUND_INFO_COLUMN_NAMES)) {
                    // 基金基本信息
                    this.fundInfoTables.add(table);
                }
            } else if (colCount == 4) {
                // 用表格的第二列的数据判断是否行业配置数据（内地）
                texts = this.getTableColTexts(table, 1);
                if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
                    this.investmentIndustryTables.add(table);
                }
            } else if (colCount == 3) {
                // 用表格的第一列的数据判断是否行业配置数据（港股通）
                if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
                    this.investmentIndustryTables.add(table);
                    continue;
                }
                // 资产配置表格识别（兼容跨页的表格）获取表格中第二列的所有文字，判断所有文字中包含"股权投资"等字符串
                texts = this.getTableColTexts(table, 1);
                Set<String> keys = ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.keySet();
                if (CollUtil.containsAny(texts, keys)) {
                    this.assetAllocationTables.add(table);
                }
            }
        }
        // 跨页的财务信息记录表（包括表头一共有10行）
        this.handleSpanningPageTables(this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
        // 跨页的份额变动记录表（包括表头一共有5行）
        this.handleSpanningPageTables(this.shareChangeTables, spanningPageShareChangeTableMap);
    }

    @Override
    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
        Map<String, Object> fundInfoMap = MapUtil.newHashMap(32);
        for (Table table : this.fundInfoTables) {
            Map<String, Object> temp = this.parseFundInfo(table);
            fundInfoMap.putAll(temp);
        }
        ReportFundInfoDTO info = new ReportFundInfoDTO(params.getFileId());
        this.buildInfo(fundInfoMap, info);
        return info;
    }

    @Override
    protected AnnuallyReportData buildReportData(ReportBaseInfoDTO reportInfo,
                                                 ReportFundInfoDTO fundInfo,
                                                 List<ReportShareChangeDTO> shareChanges,
                                                 List<ReportFinancialIndicatorsDTO> financialIndicators,
                                                 List<ReportAssetAllocationDTO> assetAllocations,
                                                 List<ReportInvestmentIndustryDTO> investmentIndustries) {
        AnnuallyReportData reportData = new AnnuallyReportData(reportInfo, fundInfo);
        reportData.setShareChange(shareChanges);
        reportData.setFinancialIndicators(financialIndicators);
        reportData.setAssetAllocation(assetAllocations);
        reportData.setInvestmentIndustry(investmentIndustries);
        return reportData;
    }

    protected List<ReportFinancialIndicatorsDTO> buildFinancialIndicatorsInfo(Integer fileId,
                                                                              Function<Table, Map<String, Object>> function) {
        List<ReportFinancialIndicatorsDTO> dtos = ListUtil.list(false);
        // 分级基金
        List<String> levels = ReportParseUtils.matchTieredFund(String.join(",", this.textList));
        // 假设这里可能存在分级基金，不存在表格跨页
        for (int k = 0; k < this.financialIndicatorsTables.size(); k++) {
            Table table = this.financialIndicatorsTables.get(k);
            int colCount = table.getColCount();
            for (int j = 1; j < colCount; j++) {
                Map<String, Object> infoMap = MapUtil.newHashMap(16);
                String year = ReportParseUtils.cleaningValue(table.getCell(0, j).getText());
                infoMap.put("年度", year);
                for (int i = 0; i < table.getRowCount(); i++) {
                    String columnName = ReportParseUtils.cleaningValue(table.getCell(i, 0).getText());
                    if (columnName == null) {
                        continue;
                    }
                    String value = ReportParseUtils.cleaningValue(table.getCell(i, j).getText());
                    infoMap.put(columnName, value);
                }
                ReportFinancialIndicatorsDTO dto = new ReportFinancialIndicatorsDTO(fileId);
                this.buildInfo(infoMap, dto);
                if (levels.size() > k) {
                    dto.setLevel(levels.get(k));
                }
                dtos.add(dto);
            }
        }
        return dtos;
    }
}
