package org.dromara.system.service.impl;

import cn.hutool.json.JSONUtil;
import cn.idev.excel.annotation.ExcelProperty;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.dromara.system.controller.TestPoi;
import org.dromara.system.domain.bo.GameAthleteBo;
import org.dromara.system.domain.bo.GameTeamBo;
import org.dromara.system.domain.vo.EnrollProjectVo;
import org.dromara.system.service.IEnrollService;
import org.dromara.system.service.IGameAthleteService;
import org.dromara.system.service.IGameEventProjectService;
import org.dromara.system.service.IGameTeamService;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Service
public class IEnrollServiceImpl implements IEnrollService {

    private final IGameEventProjectService gameEventProjectService;
    private final IGameTeamService gameTeamService;
    private final IGameAthleteService gameAthleteService;

    /**
     * 使用poi生成报名表模板
     *
     * @param response
     * @param eventId
     */
    @Override
    public void downloadTemplateForPoi(HttpServletRequest request, HttpServletResponse response, Long eventId) {
        //1.加载Excel模板文件
        String template = "template/enroll_template.xlsx";
        XSSFSheet sheet = null;
        try (
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(template);
            XSSFWorkbook xwb = new XSSFWorkbook(inputStream)) {
            sheet = xwb.getSheetAt(0);
            assert sheet != null;
            //7列3行开始横着渲染 excel表对应6行2列
            // 2. 获取赛事动态项目（赛事项目）
            Map<String, List<String>> projectMap = gameEventProjectService.mapProjectTypeAndProject(eventId);

            // 3. 渲染分类
            int currentColumnIndex = 6;
            Row row = sheet.getRow(1);
            if (row == null) {
                row = sheet.createRow(1);
            }

            for (Map.Entry<String, List<String>> entry : projectMap.entrySet()) {
                String categoryName = entry.getKey();
                List<String> projectList = entry.getValue();
                int projectCount = projectList.size();
                // 3.1 创建单元格并设置分类名称
                Cell cell = row.createCell(currentColumnIndex);
                cell.setCellValue(categoryName);

                // 3.2 合并单元格：从 currentColumnIndex 开始，合并 projectCount 个单元格
                int lastColumnIndex = currentColumnIndex + projectCount - 1;
                CellRangeAddress region = new CellRangeAddress(1, 1, currentColumnIndex, lastColumnIndex);
                sheet.addMergedRegion(region);

                // 3.3 创建样式：边框 + 居中 + 加粗
                CellStyle style = xwb.createCellStyle();
                style.setBorderTop(BorderStyle.THIN);
                style.setBorderBottom(BorderStyle.THIN);
                style.setBorderLeft(BorderStyle.THIN);
                style.setBorderRight(BorderStyle.THIN);
                style.setTopBorderColor(IndexedColors.BLACK.getIndex());
                style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
                style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
                style.setRightBorderColor(IndexedColors.BLACK.getIndex());

                style.setAlignment(HorizontalAlignment.CENTER);
                style.setVerticalAlignment(VerticalAlignment.CENTER);

                // 字体加粗
                Font font = xwb.createFont();
                font.setBold(true);
                style.setFont(font);

                // 应用样式
                cell.setCellStyle(style);

                // 3.4  更新起始列：为下一个分类腾出位置
                currentColumnIndex = lastColumnIndex + 1;
            }

            // 4. 渲染项目（在第4行，索引为3）
            currentColumnIndex = 6;
            Row projectRow = sheet.getRow(2);
            if (projectRow == null) {
                projectRow = sheet.createRow(2);
            }
            for (Map.Entry<String, List<String>> entry : projectMap.entrySet()) {
                List<String> projectList = entry.getValue();
                // 4.1 遍历当前分类下的每个项目
                for (String projectName : projectList) {
                    Cell cell = projectRow.createCell(currentColumnIndex);
                    cell.setCellValue(projectName);

                    // 3.3 创建样式：边框 + 居中 + 加粗
                    CellStyle style = xwb.createCellStyle();
                    style.setBorderTop(BorderStyle.THIN);
                    style.setBorderBottom(BorderStyle.THIN);
                    style.setBorderLeft(BorderStyle.THIN);
                    style.setBorderRight(BorderStyle.THIN);
                    style.setTopBorderColor(IndexedColors.BLACK.getIndex());
                    style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
                    style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
                    style.setRightBorderColor(IndexedColors.BLACK.getIndex());

                    style.setAlignment(HorizontalAlignment.CENTER);
                    style.setVerticalAlignment(VerticalAlignment.CENTER);

                    // 字体加粗
                    Font font = xwb.createFont();
                    font.setBold(true);
                    style.setFont(font);

                    // 应用样式
                    cell.setCellStyle(style);

                    // 移动到下一列
                    currentColumnIndex++;
                }
            }

            OutputStream outputStream = response.getOutputStream();
            // 清空response
            response.reset();
            response.setContentType("application/msexcel");//设置生成的文件类型
            response.setCharacterEncoding("UTF-8");//设置文件头编码方式和文件名
            response.setHeader("Content-Disposition", "attachment; "
                + " filename=" + new String("报名表模板.xlsx".getBytes("utf-8"), "ISO8859-1"));
            String origin = request.getHeader("Origin");
            response.addHeader("Access-Control-Allow-Origin", origin);
            xwb.write(outputStream);
        } catch (IOException e) {
            log.error("下载Excel模板异常，异常信息为：【{}】", e.getMessage(), e);
        }
    }

    /**
     * 使用poi导入报名表
     *
     * @param file
     * @param eventId
     * @return
     */
    @Override
    public Boolean importDataForPoi(MultipartFile file, Long eventId) {
        //1.解析报名信息
        List<EnrollProjectVo> enrollList = parseData(file);
        //2.保存报名信息
        this.saveEnrollData(enrollList, eventId);
        return null;
    }

    private List<EnrollProjectVo> parseData(MultipartFile file) {
        try {
            List<EnrollProjectVo> enrolls = new ArrayList<>();
            try (InputStream inputStream = file.getInputStream();
                 Workbook workbook = new XSSFWorkbook(inputStream)) {

                Sheet sheet = workbook.getSheetAt(0);

                // 获取第一行（表头），用于获取项目名称
                Row headerRow = sheet.getRow(2);
                // 动态确定有效最大列数（去除表头末尾的空列）
                int lastCellIndex = findValidLastColumnIndex(headerRow);
                List<String> projectNames = new ArrayList<>();

                // 从第6列（F列，索引5）开始收集项目名称
                for (int i = 6; i < lastCellIndex; i++) {
                    Cell cell = headerRow.getCell(i);
                    if (cell != null && cell.getStringCellValue() != null && !cell.getStringCellValue().trim().isEmpty()) {
                        projectNames.add(cell.getStringCellValue().trim());
                    } else {
                        projectNames.add("项目_" + i); // 防止空标题
                    }
                }

                // 从第3行开始读数据
                for (int i = 3; i <= sheet.getLastRowNum(); i++) {
                    Row row = sheet.getRow(i);
                    if (row == null) continue;
                    if (isRowEmpty(row, 0, lastCellIndex)) {
                        continue;
                    }

                    EnrollProjectVo enroll = new EnrollProjectVo();
                    Map<String, Boolean> selections = new LinkedHashMap<>(); // 保持顺序

                    // A列：姓名
                    Cell nameCell = row.getCell(0);
                    if (nameCell != null) {
                        enroll.setName(getCellValueAsString(nameCell));
                    }

                    // B列：性别
                    Cell sexCell = row.getCell(1);
                    if (sexCell != null) {
                        enroll.setSex(getCellValueAsString(sexCell));
                    }

                    // C列：年龄
                    Cell ageCell = row.getCell(2);
                    if (ageCell != null) {
                        enroll.setAge(getCellValueAsString(ageCell));
                    }

                    // D列：队伍名称
                    Cell teamCell = row.getCell(3);
                    if (teamCell != null) {
                        enroll.setTeamName(getCellValueAsString(teamCell));
                    }

                    // E列：领队
                    Cell leaderCell = row.getCell(4);
                    if (leaderCell != null) {
                        enroll.setLeader(getCellValueAsString(leaderCell));
                    }

                    // F列：联系方式
                    Cell phoneCell = row.getCell(5);
                    if (phoneCell != null) {
                        enroll.setPhone(getCellValueAsString(phoneCell));
                    }

                    // 从第6列开始读取项目名称
                    for (int j = 6; j < lastCellIndex; j++) {
                        Cell cell = row.getCell(j);
                        String projectName = projectNames.get(j - 6); // 对应项目名
                        boolean selected = isCellSelected(cell);
                        selections.put(projectName, selected);
                    }

                    enroll.setProjectSelections(selections);
                    enrolls.add(enroll);
                }
            }
            return enrolls;
        } catch (Exception e) {

        } finally {

        }
        return List.of();
    }

    // 辅助方法：将 Cell 转为字符串
    private static String getCellValueAsString(Cell cell) {
        if (cell == null) return "";

        switch (cell.getCellType()) {
            case Cell.CELL_TYPE_STRING:
                return cell.getStringCellValue().trim();
            case Cell.CELL_TYPE_NUMERIC:
                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return String.valueOf((int) cell.getNumericCellValue()); // 或者保留小数用 double
                }
            case Cell.CELL_TYPE_BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            default:
                return "";
        }
    }

    /**
     * 判断单元格是否表示“已选择”
     * 支持：是、yes、true、1、✔、✅、√ 等
     */
    private static boolean isCellSelected(Cell cell) {
        if (cell == null) return false;

        // 先检查单元格类型
        if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
            return cell.getBooleanCellValue();
        }
        if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
            return cell.getNumericCellValue() == 1;
        }

        String value = getCellValueAsString(cell).trim().toLowerCase();
        return !value.isEmpty() &&
            (value.equals("是") || value.equals("yes") || value.equals("true") ||
                value.equals("1") || value.contains("✔") || value.contains("✅") ||
                value.contains("√") || value.equals("×"));
    }

    /**
     * 判断某行在指定范围内是否为空（无有效数据）
     *
     * @param row      行对象
     * @param startCol 起始列索引
     * @param endCol   结束列索引（不包含）
     * @return true 表示该行为空
     */
    private static boolean isRowEmpty(Row row, int startCol, int endCol) {
        if (row == null) return true;

        for (int i = startCol; i < endCol; i++) {
            Cell cell = row.getCell(i);
            if (cell != null) {
                // 如果单元格不为null，检查其是否有非空值
                String value = getCellValueAsString(cell);
                if (value != null && !value.trim().isEmpty()) {
                    return false; // 有有效数据
                }
            }
        }
        return true; // 所有列都为空
    }

    /**
     * 找到行中最后一个“有效”单元格的索引（从右往左找第一个非空单元格）
     *
     * @param row 行对象
     * @return 有效最大列索引（不包含），即 getLastCellNum() 的合理值
     */
    private static int findValidLastColumnIndex(Row row) {
        if (row == null) return 0;

        int lastCellNum = row.getLastCellNum(); // 物理最后一列
        if (lastCellNum <= 0) return 0;

        // 从右往左扫描，找到第一个非空单元格
        for (int i = lastCellNum - 1; i >= 0; i--) {
            Cell cell = row.getCell(i);
            String value = getCellValueAsString(cell);
            if (value != null && !value.trim().isEmpty()) {
                return i + 1; // 返回有效列数（索引+1）
            }
        }
        return 0; // 全为空
    }

    /**
     * 保存数据
     *
     * @param dataList
     * @param eventId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveEnrollData(List<EnrollProjectVo> dataList, Long eventId) {
        // 1. 根据队伍分类成Map
        Map<String, List<EnrollProjectVo>> groupedByTeam = dataList.stream()
            .collect(Collectors.groupingBy(EnrollProjectVo::getTeamName));

        // 1.2 根据队伍生成号码段
        Map<String, String> numberRanges = new HashMap<>();
        Map<String, AtomicInteger> currentNumbers = new HashMap<>(); // 记录每个队伍当前分配到的号码
        AtomicInteger teamIndex = new AtomicInteger(1);
        for (Map.Entry<String, List<EnrollProjectVo>> entry : groupedByTeam.entrySet()) {
            String teamName = entry.getKey();
            String range = generateNumberRange(dataList.size(), teamIndex.getAndIncrement());
            numberRanges.put(teamName, range);

            // 解析起始号码作为初始值
            int startNum = Integer.parseInt(range.split("-")[0]);
            currentNumbers.put(teamName, new AtomicInteger(startNum));
        }

        // 2. 保存参赛队伍 & 队员
        for (Map.Entry<String, List<EnrollProjectVo>> entry : groupedByTeam.entrySet()) {
            String teamName = entry.getKey();
            List<EnrollProjectVo> athletes = entry.getValue();

            GameTeamBo gameTeamBo = new GameTeamBo();
            gameTeamBo.setEventId(eventId);
            gameTeamBo.setTeamName(teamName);
            // gameTeamBo.setTeamCode("");
            gameTeamBo.setLeader(athletes.get(0).getLeader());
            gameTeamBo.setAthleteValue(JSONUtil.toJsonStr(athletes.stream().map(EnrollProjectVo::getName).collect(Collectors.toList())));
            gameTeamBo.setAthleteNum(Long.valueOf(athletes.size()));
            gameTeamBo.setNumberRange(numberRanges.get(teamName));
            gameTeamBo.setStatus("0");
            gameTeamService.insertByBo(gameTeamBo);

            Long teamId = gameTeamBo.getTeamId();

            // 获取该队伍的当前编号计数器
            AtomicInteger currentNumber = currentNumbers.get(teamName);
            int width = (dataList.size() > 100) ? 5 : 4; // 决定格式化宽度

            // 3. 保存参赛队员
            for (EnrollProjectVo enrollInfo : athletes) {
                GameAthleteBo gameAthleteBo = new GameAthleteBo();
                gameAthleteBo.setEventId(eventId);
                gameAthleteBo.setTeamId(teamId);
                gameAthleteBo.setTeamName(teamName);

                // 分配编号：从当前计数器获取并递增
                int assignedNumber = currentNumber.getAndIncrement();
                String formattedCode = String.format("%0" + width + "d", assignedNumber);
                gameAthleteBo.setAthleteCode(formattedCode);

                gameAthleteBo.setName(enrollInfo.getName());
                gameAthleteBo.setGender(enrollInfo.getSex());
                gameAthleteBo.setAge(Long.valueOf(enrollInfo.getAge()));
                gameAthleteBo.setPhone(enrollInfo.getPhone());
                gameAthleteBo.setUnit(teamName);
                gameAthleteBo.setProjectValue(JSONUtil.toJsonStr(enrollInfo.getProjectSelections()));
                gameAthleteBo.setStatus("0");

                gameAthleteService.insertByBo(gameAthleteBo);
            }
        }
        return true;
    }


    /**
     * 生成号码段
     * 需求:
     * 不超100人，一般4位。0101-0199；超过100人，一般5位，01001-01101；
     * 根据队伍分配，最多不超过300个
     * 规则:
     * 1. 按照队伍分类，每个队伍生成一个号码段
     * 2. 直接给每个队伍分配300个号码,多余的预留起来,防止后续有新的人加入该队伍参赛,预留号码可直接分配给他
     * 3. 号码从1开始递增,高位填充0
     *
     * @param member 人数
     * @param team   当前是第几队
     * @return 号码段字符串，如 "0001-0300" 或 "00001-00300"
     */
    public static String generateNumberRange(int member, int team) {
        // 每个队伍固定分配300个号码
        int start = 1 + (team - 1) * 300;
        int end = 300 * team;

        // 判断使用4位还是5位
        int width = (member > 100) ? 5 : 4;

        String startStr = String.format("%0" + width + "d", start);
        String endStr = String.format("%0" + width + "d", end);

        return startStr + "-" + endStr;
    }

    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {
            System.out.println(generateNumberRange(100, i));
        }
    }
}
