package com.bonus.material.codeCollection.service.impl;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.bonus.common.biz.constant.GlobalConstants;
import com.bonus.common.core.utils.poi.ExcelUtil;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.material.codeCollection.domain.WsMaInfo;
import com.bonus.material.codeCollection.mapper.WsMaInfoMapper;
import com.bonus.material.codeCollection.service.WsMaInfoService;
import com.bonus.material.ma.domain.Type;
import com.bonus.material.ma.domain.vo.ExceptionEnum;
import com.bonus.material.ma.domain.vo.MaTypeVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.hibernate.validator.internal.util.StringHelper;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * {@code WsMaInfoServiceImpl}
 * <p>
 * 机具信息服务实现类，实现了 {@link WsMaInfoService} 接口。
 * 提供对 {@code ws_ma_info} 表的增删改查业务逻辑，并统一返回 {@link AjaxResult} 格式结果。
 * </p>
 *
 * <p>核心功能：</p>
 * <ul>
 *     <li>根据ID获取机具信息</li>
 *     <li>获取全部机具信息</li>
 *     <li>新增机具信息</li>
 *     <li>更新机具信息</li>
 *     <li>删除机具信息</li>
 * </ul>
 */
@Slf4j
@Service
public class WsMaInfoServiceImpl implements WsMaInfoService {

    /**
     * 注入 Mapper，执行实际的数据库操作
     */
    @Resource
    private WsMaInfoMapper mapper;

    /**
     * 根据主键 ID 获取单条机具信息
     *
     * @param id 机具主键ID
     * @return AjaxResult，成功时返回 WsMaInfo 数据，失败时返回提示信息
     */
    @Override
    public AjaxResult getById(Integer id) {
        try {
            WsMaInfo info = mapper.selectById(id);
            return ObjectUtils.isNotEmpty(info) ? AjaxResult.success(info) : AjaxResult.error("未找到对应的机具信息，ID: " + id);
        } catch (Exception e) {
            log.error(e.getMessage());
            return AjaxResult.error("未找到对应的机具信息，ID: " + id);
        }
    }

    /**
     * 获取全部机具信息列表（无分页）
     *
     * @return List<WsMaInfo> 数据集合，由 Controller 封装为 AjaxResult
     */
    @Override
    public List<WsMaInfo> getAll(WsMaInfo info) {
        return mapper.selectAll(info);
    }

    /**
     * 新增一条机具信息记录
     *
     * @param info 机具实体对象，需包含有效字段（如 maName, maCode 等）
     * @return AjaxResult，成功或失败信息
     */
    @Override
    public AjaxResult save(WsMaInfo info) {
        if (CollectionUtils.isEmpty(info.getMaCodeList())) {
            return AjaxResult.error("机具编码不能为空");
        }
        try {
            for (String maCode : info.getMaCodeList()) {
                info.setMaCode(maCode);
                int i = mapper.existsByModelAndCode(info.getMaCode());
                if (i > 0) {
                    return AjaxResult.error(info.getMaCode() + "：该机具规格与编码已存在，请勿重复添加！");
                }
            }
            int result = 0;
            for (String maCode : info.getMaCodeList()) {
                info.setMaCode(maCode);
                result = mapper.insert(info);
            }
            return result > 0 ? AjaxResult.success("新增成功") : AjaxResult.error("新增失败");
        } catch (Exception e) {
            log.error(e.getMessage());
            return AjaxResult.error("新增失败");
        }

    }

    /**
     * 根据 ID 更新已有机具信息
     *
     * @param info 包含更新字段及主键ID的机具实体
     * @return AjaxResult，操作成功与否
     */
    @Override
    public AjaxResult update(WsMaInfo info) {
        try {
            if (info.getId() == null) {
                return AjaxResult.error("ID不能为空");
            }
            int i = mapper.existsByModelAndCode(info.getMaCode());
            if (i > 1) {
                return AjaxResult.error("该机具规格与编码已存在，请勿重复添加！");
            }
            int result = mapper.update(info);
            return result > 0
                    ? AjaxResult.success("更新成功")
                    : AjaxResult.error("更新失败");
        } catch (Exception e) {
            log.error(e.getMessage());
            return AjaxResult.error("更新失败");
        }
    }

    /**
     * 根据主键 ID 删除机具信息记录
     *
     * @param id 待删除记录的主键 ID
     * @return AjaxResult，操作是否成功
     */
    @Override
    public AjaxResult delete(Integer id) {
        try {
            int result = mapper.deleteById(id);
            return result > 0
                    ? AjaxResult.success("删除成功")
                    : AjaxResult.error("删除失败");
        } catch (Exception e) {
            log.error(e.getMessage());
            return AjaxResult.error("删除失败");
        }
    }

    /**
     * 获取机具类型下拉选
     *
     * @return 机具类型集合
     */
    @Override
    public AjaxResult getMaTypeData() {
        try {
            List<Map<String, Objects>> maTypeData = mapper.getMaTypeData();
            return ObjectUtils.isNotEmpty(maTypeData) ? AjaxResult.success(maTypeData) : AjaxResult.success();
        } catch (Exception e) {
            log.error(e.getMessage());
            return AjaxResult.error("");
        }
    }

    /**
     * 获取机具规格下拉选
     *
     * @param parentId 父类id
     * @return 机具规格集合
     */
    @Override
    public AjaxResult getMaModeData(Integer parentId) {
        try {
            List<Map<String, Objects>> maModeData = mapper.getMaModeData(parentId);
            return ObjectUtils.isNotEmpty(maModeData) ? AjaxResult.success(maModeData) : AjaxResult.error("");
        } catch (Exception e) {
            log.error(e.getMessage());
            return AjaxResult.error("");
        }
    }

    /**
     * 获取出厂厂家
     *
     * @return 出厂厂家集合
     */
    @Override
    public AjaxResult getSupplier() {
        try {
            List<Map<String, Objects>> supplier = mapper.getSupplier();
            return ObjectUtils.isNotEmpty(supplier) ? AjaxResult.success(supplier) : AjaxResult.error("");
        } catch (Exception e) {
            log.error(e.getMessage());
            return AjaxResult.error("");
        }
    }

    /**
     * 更新时间
     *
     * @param info
     * @return 条数
     */
    @Override
    public AjaxResult updateCheckTime(WsMaInfo  info) {
        try {
            int i = mapper.updateCheckTime(info);
            return AjaxResult.success("更新成功");
        } catch (Exception e) {
            log.error(e.getMessage());
            return AjaxResult.error("更新失败");
        }
    }

    @Override
    public List<WsMaInfo> getGadgetList(WsMaInfo info) {
        try {
            return mapper.getGadgetList(info);
        } catch (Exception e) {
            log.error("查询小工具编码信息列表：", e.getMessage());
            return new ArrayList<>();
        }
    }

    @Override
    public AjaxResult addWsMaInfoData(WsMaInfo info) {
        try {
            info.setOptUser(SecurityUtils.getLoginUser().getSysUser().getNickName());
            //查询是否存在
            int count = mapper.selectCountByCode(info);
            if (count > 0){
                return AjaxResult.error("该类型下此编码已存在");
            }
            int i = mapper.addWsMaInfoData(info);
            return i > 0 ? AjaxResult.success("添加小工具编码信息列表成功") : AjaxResult.error("添加小工具编码信息列表失败");
        } catch (Exception e) {
            log.error("添加小工具编码信息列表：", e.getMessage());
            return AjaxResult.error("添加小工具编码信息列表失败");
        }
    }

    @Override
    public AjaxResult delGadget(WsMaInfo info) {
        try {
            int i = mapper.delGadget(info);
            return i > 0 ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
        } catch (Exception e) {
            log.error("删除小工具编码信息列表：", e.getMessage());
            return AjaxResult.error("删除失败");
        }
    }

    @Override
    public AjaxResult getGadgetInfo(Integer id) {
        try {
            WsMaInfo info = mapper.getGadgetInfo(id);
            return AjaxResult.success(info);
        } catch (Exception e) {
            log.error("查询小工具编码信息列表：", e.getMessage());
            return AjaxResult.error("查询失败");
        }
    }

    @Override
    public AjaxResult updateGadgetInfo(WsMaInfo info) {
        try {
            if (info.getId() == null) {
                return AjaxResult.error("ID不能为空");
            }
            //查询是否存在,如果存在id不同则不能更新
            //用传入的类型、型号、编号查询记录
            WsMaInfo wsMaInfo = mapper.getInfoByTypeAndModelAndCode(info);
            if (wsMaInfo != null && !wsMaInfo.getId().equals(info.getId())) {
                return AjaxResult.error("该类型下此编码已存在");
            }
            info.setOptUser(SecurityUtils.getLoginUser().getSysUser().getNickName());
            int i = mapper.updateGadgetInfo(info);
            return i > 0 ? AjaxResult.success("更新成功") : AjaxResult.error("更新失败");
        } catch (Exception e) {
            log.error("更新小工具编码信息列表：", e.getMessage());
            return AjaxResult.error("更新失败");
        }
    }

    /**
     * 小工具导入模版下载
     * @param response
     */
    @Override
    public void downLoadTemplate(HttpServletResponse response) {
        //模板名称
        String templateName = "机具检验标识信息导入模板.xls";
        OutputStream out = null;
        InputStream input =null;
        try {
            input = this.getClass().getClassLoader().getResourceAsStream("template/机具检验标识信息导入模板.xls");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + new String((templateName).getBytes(), "iso-8859-1"));
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            out = response.getOutputStream();
            // 缓冲区
            byte[] buffer = new byte[1024];
            int bytesToRead = -1;
            // 通过循环将读入内容输出到浏览器中
            while ((bytesToRead = input.read(buffer)) != -1) {
                out.write(buffer, 0, bytesToRead);
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            IOUtils.closeQuietly(input);
            IOUtils.closeQuietly(out);
        }
    }

    @Override
    public AjaxResult importTbData(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        if (fileName != null) {
            String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1);
            if (!GlobalConstants.XLSX.equalsIgnoreCase(fileExtension) && !GlobalConstants.XLS.equalsIgnoreCase(fileExtension)) {
                return AjaxResult.error("导入失败：文件后缀名不符合要求,必须为xlsx或xls结尾");
            }
        }

        try {
            InputStream inputStream = file.getInputStream();
            Workbook workbook = WorkbookFactory.create(inputStream);
            Sheet sheet = workbook.getSheetAt(0);

            // 得到Excel的行数（跳过表头行）
            int totalRows = sheet.getPhysicalNumberOfRows();
            if (totalRows <= 1) {
                throw new IllegalArgumentException("导入失败：Excel文件中没有数据，请检查后重新导入");
            }

            // 读取表头行（第一行）
            Row headerRow = sheet.getRow(1);
            if (headerRow == null) {
                throw new IllegalArgumentException("导入失败：文件中没有表头");
            }

            // 验证表头
            validateHeader(headerRow);

            List<WsMaInfo> wsMaInfos = new ArrayList<>();
            int successCount = 0;
            int failCount = 0;
            List<String> errorMessages = new ArrayList<>();

            // 从第二行开始读取数据（索引1）
            for (int rowNum = 2; rowNum < totalRows; rowNum++) {
                Row row = sheet.getRow(rowNum);
                if (row == null) {
                    continue;
                }

                try {
                    WsMaInfo wsMaInfo = parseRowToWsMaInfo(row);
                    if (wsMaInfo != null) {
                        wsMaInfos.add(wsMaInfo);
                        // 新增操作
                        wsMaInfo.setOptUser(SecurityUtils.getLoginUser().getSysUser().getNickName());
                        mapper.addWsMaInfoData(wsMaInfo);
                        successCount++;
                    }
                } catch (Exception e) {
                    failCount++;
                    errorMessages.add("第 " + (rowNum + 1) + " 行数据解析失败: " + e.getMessage());
                }
            }

            // 处理结果返回
            if (failCount == 0) {
                return AjaxResult.success("导入成功，共导入 " + successCount + " 条数据");
            } else {
                String errorMsg = "导入完成，成功 " + successCount + " 条，失败 " + failCount + " 条。";
                if (!errorMessages.isEmpty()) {
                    errorMsg += "错误信息：" + String.join("; ", errorMessages);
                }
                return AjaxResult.error(errorMsg);
            }

        } catch (IOException e) {
            log.error("导入文件读取失败", e);
            return AjaxResult.error("导入失败：文件读取异常");
        } catch (IllegalArgumentException e) {
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
            log.error("导入过程发生异常", e);
            return AjaxResult.error("导入失败：系统异常");
        }
    }

    /**
     * 验证表头格式
     */
    private void validateHeader(Row headerRow) {
        String[] expectedHeaders = {
                "序号", "机具名称", "规格型号", "机具编号", "本次检验时间",
                "下次检验时间", "检修员", "检验员", "联系方式", "结果"
        };

        int cellCount = headerRow.getPhysicalNumberOfCells();
        if (cellCount < expectedHeaders.length) {
            throw new IllegalArgumentException("导入失败：表头列数不足，请检查导入模板");
        }

        for (int i = 0; i < expectedHeaders.length; i++) {
            Cell cell = headerRow.getCell(i);
            if (cell == null) {
                throw new IllegalArgumentException("导入失败：第 " + (i + 1) + " 列表头为空");
            }

            String headerValue = getCellValueAsString(cell).trim();
            if (!expectedHeaders[i].equals(headerValue)) {
                throw new IllegalArgumentException("导入失败：第 " + (i + 1) + " 列表头 '" + headerValue +
                        "' 与预期 '" + expectedHeaders[i] + "' 不符");
            }
        }
    }

    /**
     * 解析单行数据到WsMaInfo对象
     */
    private WsMaInfo parseRowToWsMaInfo(Row row) {
        WsMaInfo wsMaInfo = new WsMaInfo();

        // 机具名称
        String maName = getCellValueAsString(row.getCell(1));
        if (StringHelper.isNullOrEmptyString(maName)){
            throw new IllegalArgumentException("机具名称不能为空");
        }
        wsMaInfo.setMaName(maName);

        // 规格型号
        String maModel = getCellValueAsString(row.getCell(2));
        if (StringHelper.isNullOrEmptyString(maModel)){
            throw new IllegalArgumentException("规格型号不能为空");
        }
        wsMaInfo.setMaModel(maModel);

        // 机具编号
        String maCode = getCellValueAsString(row.getCell(3));
        if (StringUtils.isEmpty(maCode)) {
            throw new IllegalArgumentException("机具编号不能为空");
        }
        wsMaInfo.setMaCode(maCode);

        // 本次检验时间
        String thisCheckTime = getCellValueAsString(row.getCell(4));
        if (!isValidDate(thisCheckTime)) {
            throw new IllegalArgumentException("本次检验时间格式不正确");
        }
        wsMaInfo.setThisCheckTime(thisCheckTime);

        // 下次检验时间
        String nextCheckTime = getCellValueAsString(row.getCell(5));
        if (!isValidDate(nextCheckTime)) {
            throw new IllegalArgumentException("下次检验时间格式不正确");
        }
        wsMaInfo.setNextCheckTime(nextCheckTime);

        // 检修员
        wsMaInfo.setRepairMan(getCellValueAsString(row.getCell(6)));

        // 检验员
        wsMaInfo.setCheckMan(getCellValueAsString(row.getCell(7)));

        // 联系方式
        wsMaInfo.setPhone(getCellValueAsString(row.getCell(8)));

        // 结果
        String result = getCellValueAsString(row.getCell(9));
        if (!"合格".equals(result) && !"不合格".equals(result)) {
            throw new IllegalArgumentException("检验结果必须是'合格'或'不合格'");
        }
        wsMaInfo.setResult(result);

        // 验证设备类型和规格型号的层级关系
        validateTypeHierarchy(wsMaInfo, maName, maModel);

        //判断该类型下编码是否已存在
        WsMaInfo info = mapper.getInfoByTypeAndModelAndCode(wsMaInfo);
        if (info != null){
            throw new IllegalArgumentException("该类型下编码已存在");
        }

        return wsMaInfo;
    }

    /**
     * 验证设备类型和规格型号的层级关系
     */
    /**
     * 通过关联查询验证层级关系（更高效）
     */
    private void validateTypeHierarchy(WsMaInfo wsMaInfo, String typeName, String modelName) {
        // 使用关联查询直接验证层级关系
        Type relation = mapper.selectTypeRelation("3", typeName, "4", modelName);

        if (relation == null) {
            throw new IllegalArgumentException("规格型号 '" + modelName + "' 不属于设备类型 '" + typeName + "' 或不存在");
        }

        wsMaInfo.setModelId(String.valueOf(relation.getTypeId()));
    }

    /**
     * 更新已存在的记录
     */
    private void updateExistingRecord(WsMaInfo existing, WsMaInfo newData) {
        existing.setThisCheckTime(newData.getThisCheckTime());
        existing.setNextCheckTime(newData.getNextCheckTime());
        existing.setRepairMan(newData.getRepairMan());
        existing.setCheckMan(newData.getCheckMan());
        existing.setPhone(newData.getPhone());
        existing.setResult(newData.getResult());
        existing.setOptTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        existing.setOptUser(SecurityUtils.getUsername());
    }

    /**
     * 获取单元格值的通用方法
     */
    private String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());
                } else {
                    return String.valueOf((int) cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }

    /**
     * 验证日期格式
     */
    private boolean isValidDate(String dateStr) {
        if (StringUtils.isEmpty(dateStr)) {
            return false;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            sdf.setLenient(false);
            sdf.parse(dateStr);
            return true;
        } catch (ParseException e) {
            return false;
        }
    }

}
