package com.ruoyi.tjfx.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.tjfx.common.PageResponse;
import com.ruoyi.tjfx.entity.*;
import com.ruoyi.tjfx.mapper.BaseDataMapper;
import com.ruoyi.tjfx.mapper.CategoryMapper;
import com.ruoyi.tjfx.service.BaseDataService;
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 javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;

@Service
public class BaseDataServiceImpl implements BaseDataService {
    @Autowired
    private BaseDataMapper baseDataMapper;
    @Autowired
    private CategoryMapper categoryMapper;

    @Override
    public List<BaseData> listAll() {
        return baseDataMapper.selectList(null);
    }

    @Override
    public BaseData getById(Long id) {
        return baseDataMapper.selectById(id);
    }

    @Override
    public void add(BaseData baseData) {
        baseDataMapper.insert(baseData);
    }

    @Override
    public void update(Long id, BaseData baseData) {
        baseData.setId(id);
        baseDataMapper.updateById(baseData);
    }

    @Override
    public void delete(Long id) {
        baseDataMapper.deleteById(id);
    }

    @Override
    public void deleteBatch(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return;
        }
        baseDataMapper.deleteBatchIds(ids);
    }
    @Override
    public PageResponse<BaseDataVO> getPage(Integer page, Integer pageSize, String productCode, String productName, Long categoryId) {
        Page<BaseDataVO> pageParam = new Page<>(page, pageSize);

        // 执行 join 查询
        IPage<BaseDataVO> pageResult = baseDataMapper.selectPageWithJoin(
            pageParam, productCode, productName, categoryId
        );

        // 构建 PageResponse（关键在这）
        PageResponse.Pagination pagination = new PageResponse.Pagination(
            pageResult.getTotal(),
            Math.toIntExact(pageResult.getCurrent()), // 当前页
            Math.toIntExact(pageResult.getSize())     // 页大小
        );

        return new PageResponse<>(pageResult.getRecords(), pagination);
    }
    @Override
    @Transactional
    public void importExcel(MultipartFile file, Long categoryId) {
        try {
            Category category = categoryMapper.selectById(categoryId);
            if (category == null) {
                throw new RuntimeException("分类不存在");
            }

            // 初始化数据容器
            List<Map<Integer, String>> dataList = new ArrayList<>();
            List<String> headers = new ArrayList<>();

            // 使用 EasyExcel 读取表头 + 数据
            try (InputStream inputStream = file.getInputStream()) {
                EasyExcel.read(inputStream)
                    .headRowNumber(0) // 表头行为第0行
                    .sheet()
                    .registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
                        private boolean isHeaderParsed = false;

                        @Override
                        public void invoke(Map<Integer, String> data, AnalysisContext context) {
                            if (!isHeaderParsed) {
                                for (Map.Entry<Integer, String> entry : data.entrySet()) {
                                    headers.add(entry.getValue());
                                }
                                isHeaderParsed = true;
                            } else {
                                dataList.add(data);
                            }
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext context) {
                            // nothing
                        }
                    }).doRead();
            }

            if (dataList.isEmpty()) {
                throw new RuntimeException("导入数据为空");
            }

            List<BaseData> insertList = new ArrayList<>();
            List<String> errors = new ArrayList<>();
            Set<String> duplicateCheck = new HashSet<>();

            // 固定列索引
            int codeCol = 0;
            int nameCol = 1;
            int brandCol = 2;
            int categoryNameCol = 3;
            int extendStartCol = 4; // E列开始（0-based index）

            ObjectMapper objectMapper = new ObjectMapper();

            for (int i = 0; i < dataList.size(); i++) {
                Map<Integer, String> rowMap = dataList.get(i);
                int rowNum = i + 2;

                String productCode = rowMap.getOrDefault(codeCol, "").trim();
                String productName = rowMap.getOrDefault(nameCol, "").trim();
                String brand = rowMap.getOrDefault(brandCol, "").trim();
                String categoryNameVal = rowMap.getOrDefault(categoryNameCol, "").trim();

                if (productCode.isEmpty() || productName.isEmpty()) {
                    errors.add("第" + rowNum + "行：商品编号或商品名称不能为空");
                    continue;
                }

                if (!duplicateCheck.add(productCode)) {
                    errors.add("第" + rowNum + "行：商品编号\"" + productCode + "\"在Excel中重复");
                    continue;
                }

                // 处理分类规格字段
                Map<String, String> categorySpecsMap = new LinkedHashMap<>();
                for (int col = extendStartCol; col < headers.size(); col++) {
                    String key = headers.get(col);
                    String value = rowMap.getOrDefault(col, "").trim();
                    categorySpecsMap.put(key, value);
                }

                BaseData data = new BaseData();
                data.setProductCode(productCode);
                data.setProductName(productName);
                data.setBrand(brand);
                data.setCategoryId(categoryId);
                data.setCategoryName(categoryNameVal);
                data.setCategorySpecs(objectMapper.writeValueAsString(categorySpecsMap));
                data.setCreatedAt(LocalDateTime.now());
                data.setUpdatedAt(LocalDateTime.now());

                insertList.add(data);
            }

            // 去重：数据库中已存在的商品编号
            if (!insertList.isEmpty()) {
                List<String> existCodes = baseDataMapper.selectExistingProductCodes(
                    insertList.stream().map(BaseData::getProductCode).collect(Collectors.toList())
                );
                Set<String> existSet = new HashSet<>(existCodes);
                insertList = insertList.stream()
                    .filter(item -> {
                        if (existSet.contains(item.getProductCode())) {
                            errors.add("商品编号\"" + item.getProductCode() + "\"已存在数据库中");
                            return false;
                        }
                        return true;
                    }).collect(Collectors.toList());
            }

            // 批量插入
            if (!insertList.isEmpty()) {
                baseDataMapper.insertBatch(insertList);
            }

            if (!errors.isEmpty()) {
                throw new RuntimeException("导入完成，但存在以下错误：\n" + String.join("\n", errors));
            }

        } catch (Exception e) {
            throw new RuntimeException("Excel导入失败: " + e.getMessage(), e);
        }
    }

    @Override
    public void exportExcel(Long categoryId, HttpServletResponse response) {
        try (Workbook workbook = new XSSFWorkbook()) {
            // 查询分类
            Category category = categoryMapper.selectById(categoryId);
            if (category == null) {
                throw new RuntimeException("分类不存在");
            }

            // 查询数据
            List<BaseDataVO> baseDataList = baseDataMapper.findByCategoryId(categoryId);
            if (baseDataList.isEmpty()) {
                throw new RuntimeException("该分类下暂无数据");
            }

            // 提取所有扩展字段 key（即分类规格里的字段）
            Set<String> specKeys = new LinkedHashSet<>();
            for (BaseDataVO baseData : baseDataList) {
                String specJson = baseData.getCategorySpecs();
                if (specJson != null && !specJson.isEmpty()) {
                    try {
                        Map<String, String> specMap = new ObjectMapper().readValue(specJson, new TypeReference<Map<String, String>>() {});
                        specKeys.addAll(specMap.keySet());
                    } catch (Exception e) {
                        throw new RuntimeException("分类规格格式有误：" + specJson);
                    }
                }
            }

            // 创建 Sheet
            Sheet sheet = workbook.createSheet("基准数据");

            // 设置表头：固定字段 + 动态分类规格字段（不包含时间）
            String[] fixedHeaders = {"商品编号", "商品名称", "品牌", "所属分类"};
            List<String> allHeaders = new ArrayList<>(Arrays.asList(fixedHeaders));
            allHeaders.addAll(specKeys);

            Row headerRow = sheet.createRow(0);
            for (int i = 0; i < allHeaders.size(); i++) {
                headerRow.createCell(i).setCellValue(allHeaders.get(i));
            }

            // 写入数据
            for (int i = 0; i < baseDataList.size(); i++) {
                BaseDataVO baseData = baseDataList.get(i);
                Row row = sheet.createRow(i + 1);
                int col = 0;

                row.createCell(col++).setCellValue(Optional.ofNullable(baseData.getProductCode()).orElse(""));
                row.createCell(col++).setCellValue(Optional.ofNullable(baseData.getProductName()).orElse(""));
                row.createCell(col++).setCellValue(Optional.ofNullable(baseData.getBrand()).orElse(""));
                row.createCell(col++).setCellValue(category.getName());

                // 解析分类规格
                Map<String, String> specMap = new HashMap<>();
                if (baseData.getCategorySpecs() != null && !baseData.getCategorySpecs().isEmpty()) {
                    try {
                        specMap = new ObjectMapper().readValue(baseData.getCategorySpecs(), new TypeReference<Map<String, String>>() {});
                    } catch (Exception e) {
                        // 忽略解析失败的行
                    }
                }

                // 写入扩展字段
                for (String key : specKeys) {
                    row.createCell(col++).setCellValue(specMap.getOrDefault(key, ""));
                }
            }

            // 自动列宽
            for (int i = 0; i < allHeaders.size(); i++) {
                sheet.autoSizeColumn(i);
            }

            // 设置响应头
            String fileName = URLEncoder.encode("基准数据_" + category.getName() + "_" + System.currentTimeMillis() + ".xlsx", "UTF-8")
                .replaceAll("\\+", "%20");
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + fileName);

            // 输出到响应流
            workbook.write(response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            try {
                response.reset();
                response.setContentType("application/json");
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write("{\"success\":false,\"message\":\"" + e.getMessage() + "\"}");
            } catch (IOException ex) {
                throw new RuntimeException("写入错误信息失败: " + ex.getMessage(), ex);
            }
        }
    }

    private List<List<String>> buildHead(List<Map<String, Object>> data) {
        if (data == null || data.isEmpty()) {
            return new ArrayList<>();
        }

        List<List<String>> headList = new ArrayList<>();
        for (String key : data.get(0).keySet()) {
            headList.add(Collections.singletonList(key));
        }
        return headList;
    }
}
