package com.hotwj.platform.noticeManagerment.signFileDetail.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotwj.platform.common.helper.DriverLoginContextHelper;
import com.hotwj.platform.common.service.ITemplateService;
import com.hotwj.platform.flow.domain.SysFlowInstance;
import com.hotwj.platform.flow.domain.SysFlowTask;
import com.hotwj.platform.flow.mapper.SysFlowInstanceMapper;
import com.hotwj.platform.flow.mapper.SysFlowTaskMapper;
import com.hotwj.platform.flow.service.ISysFlowService;
import com.hotwj.platform.integration.ocr.SignatureVerifyService;
import com.hotwj.platform.noticeManagerment.noticeSignDocument.domain.vo.HotNoticeSignDocumentVo;
import com.hotwj.platform.noticeManagerment.noticeSignDocument.service.IHotNoticeSignDocumentService;
import com.hotwj.platform.noticeManagerment.signFileDetail.domain.HotSignFileDetail;
import com.hotwj.platform.noticeManagerment.signFileDetail.domain.bo.HotSignFileDetailBo;
import com.hotwj.platform.noticeManagerment.signFileDetail.domain.vo.HotSignFileDetailVo;
import com.hotwj.platform.noticeManagerment.signFileDetail.mapper.HotSignFileDetailMapper;
import com.hotwj.platform.noticeManagerment.signFileDetail.service.IHotSignFileDetailService;
import com.hotwj.platform.reportStatistics.integration.GotenbergClient;
import com.hotwj.platform.reportStatistics.template.VelocityTemplateRenderer;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.VelocityContext;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 签订文件明细Service业务层处理
 *
 * @author shihongwei
 * @date 2026-01-14
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class HotSignFileDetailServiceImpl implements IHotSignFileDetailService {
    private static final long STAFF_TYPE_ALL = 4L;
    private static final long STAFF_TYPE_DRIVER = 1L;
    private static final long STAFF_TYPE_DRIVER_PRACTITIONER = 3L;

    private final HotSignFileDetailMapper baseMapper;
    private final ISysFlowService flowService;
    private final IHotNoticeSignDocumentService documentService;
    private final SysFlowInstanceMapper instanceMapper;
    private final SysFlowTaskMapper taskMapper;
    private final ITemplateService templateService;
    private final GotenbergClient gotenbergClient;
    private final VelocityTemplateRenderer velocityTemplateRenderer;
    private final SignatureVerifyService signatureVerifyService;

    /**
     * 查询签订文件明细
     *
     * @param id 主键
     * @return 签订文件明细
     */
    @Override
    public HotSignFileDetailVo queryById(Long id) {
        HotSignFileDetailVo detailVo = baseMapper.selectVoById(id);
        if (detailVo == null) {
            return null;
        }
        List<HotSignFileDetailVo> records = new ArrayList<>(1);
        records.add(detailVo);
        fillTodoTaskId(records);
        fillTemplateContent(detailVo);
        return detailVo;
    }

    private void fillTemplateContent(HotSignFileDetailVo detailVo) {
        if (detailVo == null || detailVo.getIssueFileId() == null) {
            return;
        }
        HotNoticeSignDocumentVo documentVo = documentService.queryById(detailVo.getIssueFileId());
        if (documentVo == null) {
            return;
        }
        detailVo.setFileName(documentVo.getFileName());
        String templateContent = documentVo.getContent();
        if (StringUtils.isBlank(templateContent)) {
            detailVo.setContent(templateContent);
            return;
        }
        Map<String, Object> dataMap = templateService.prepareDataMapForSignDetail(detailVo.getId());
        detailVo.setContent(templateService.fillTemplate(templateContent, dataMap));
    }

    @Override
    public void exportDetailPdf(Long id, HttpServletResponse response) {
        HotSignFileDetailVo detailVo = queryById(id);
        if (detailVo == null) {
            throw new ServiceException("签订文件明细不存在");
        }
        String title = StringUtils.isNotBlank(detailVo.getFileName()) ? detailVo.getFileName() : "签订文件详情";
        String body = StringUtils.defaultString(detailVo.getContent());
        VelocityContext layoutContext = new VelocityContext();
        layoutContext.put("title", title);
        layoutContext.put("bodies", List.of("<div style=\"padding:0 10px;\">" + body + "</div>"));
        String finalHtml = velocityTemplateRenderer.render("templates/layout/printLayout.html.vm", layoutContext);
        byte[] pdfBytes = gotenbergClient.convertHtmlToPdf(finalHtml);
        try {
            FileUtils.setAttachmentResponseHeader(response, title + ".pdf");
            response.setContentType("application/pdf");
            response.getOutputStream().write(pdfBytes);
        } catch (IOException e) {
            log.error("导出签订文件详情PDF失败, id={}", id, e);
            throw new ServiceException("导出PDF失败");
        }
    }

    /**
     * 分页查询签订文件明细列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 签订文件明细分页列表
     */
    @Override
    public TableDataInfo<HotSignFileDetailVo> queryPageList(HotSignFileDetailBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<HotSignFileDetail> lqw = buildQueryWrapper(bo);
        Page<HotSignFileDetailVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        fillTodoTaskId(result.getRecords());
        return TableDataInfo.build(result);
    }

    private void fillTodoTaskId(List<HotSignFileDetailVo> records) {
        if (records == null || records.isEmpty()) {
            return;
        }

        List<String> businessIds = records.stream()
                .map(HotSignFileDetailVo::getId)
                .filter(id -> id != null)
                .map(String::valueOf)
                .distinct()
                .toList();

        if (businessIds.isEmpty()) {
            return;
        }

        List<SysFlowInstance> instances = instanceMapper.selectList(
                Wrappers.<SysFlowInstance>lambdaQuery()
                        .eq(SysFlowInstance::getFlowCode, "SIGN_FILE")
                        .eq(SysFlowInstance::getStatus, 0)
                        .in(SysFlowInstance::getBusinessId, businessIds)
        );

        if (instances == null || instances.isEmpty()) {
            return;
        }

        Map<String, String> businessIdToInstanceId = instances.stream()
                .collect(Collectors.toMap(SysFlowInstance::getBusinessId, SysFlowInstance::getInstanceId, (a, b) -> a));

        List<String> instanceIds = instances.stream()
                .map(SysFlowInstance::getInstanceId)
                .distinct()
                .toList();

        List<SysFlowTask> tasks = taskMapper.selectList(
                Wrappers.<SysFlowTask>lambdaQuery()
                        .in(SysFlowTask::getInstanceId, instanceIds)
        );

        if (tasks == null || tasks.isEmpty()) {
            return;
        }

        Map<String, String> instanceIdToTaskId = tasks.stream()
                .collect(Collectors.toMap(SysFlowTask::getInstanceId, SysFlowTask::getTaskId, (a, b) -> a));

        for (HotSignFileDetailVo record : records) {
            if (record == null || record.getId() == null) {
                continue;
            }
            String instanceId = businessIdToInstanceId.get(String.valueOf(record.getId()));
            if (instanceId == null) {
                continue;
            }
            record.setTaskId(instanceIdToTaskId.get(instanceId));
        }
    }

    /**
     * 查询符合条件的签订文件明细列表
     *
     * @param bo 查询条件
     * @return 签订文件明细列表
     */
    @Override
    public List<HotSignFileDetailVo> queryList(HotSignFileDetailBo bo) {
        LambdaQueryWrapper<HotSignFileDetail> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<HotSignFileDetail> buildQueryWrapper(HotSignFileDetailBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HotSignFileDetail> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(HotSignFileDetail::getId);
        lqw.eq(bo.getCompanyId() != null, HotSignFileDetail::getCompanyId, bo.getCompanyId());
        lqw.eq(bo.getIssueFileId() != null, HotSignFileDetail::getIssueFileId, bo.getIssueFileId());
        lqw.eq(bo.getStaffId() != null, HotSignFileDetail::getStaffId, bo.getStaffId());
        lqw.like(StringUtils.isNotBlank(bo.getStaffName()), HotSignFileDetail::getStaffName, bo.getStaffName());
        if (bo.getStaffType() != null) {
            if (Objects.equals(bo.getStaffType(), STAFF_TYPE_ALL)) {
                // 全部人员不追加staffType过滤
            } else if (Objects.equals(bo.getStaffType(), STAFF_TYPE_DRIVER_PRACTITIONER)) {
                // 从业人员查询口径：覆盖驾驶员表中的驾驶员与从业人员
                lqw.in(HotSignFileDetail::getStaffType, STAFF_TYPE_DRIVER, STAFF_TYPE_DRIVER_PRACTITIONER);
            } else {
                lqw.eq(HotSignFileDetail::getStaffType, bo.getStaffType());
            }
        }
        lqw.eq(bo.getSignTime() != null, HotSignFileDetail::getSignTime, bo.getSignTime());
        lqw.eq(bo.getSignStatus() != null, HotSignFileDetail::getSignStatus, bo.getSignStatus());
        lqw.eq(bo.getExpireTime() != null, HotSignFileDetail::getExpireTime, bo.getExpireTime());
        lqw.eq(bo.getIsArchived() != null, HotSignFileDetail::getIsArchived, bo.getIsArchived());
        lqw.eq(bo.getIsDeleted() != null, HotSignFileDetail::getIsDeleted, bo.getIsDeleted());
        return lqw;
    }

    /**
     * 新增签订文件明细
     *
     * @param bo 签订文件明细
     * @return 是否新增成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(HotSignFileDetailBo bo) {
        HotSignFileDetail add = MapstructUtils.convert(bo, HotSignFileDetail.class);
        if (add.getSignStatus() == null) {
            add.setSignStatus(0L);
        }
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改签订文件明细
     *
     * @param bo 签订文件明细
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(HotSignFileDetailBo bo) {
        HotSignFileDetail update = MapstructUtils.convert(bo, HotSignFileDetail.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(HotSignFileDetail entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除签订文件明细信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 完成文件签署（更新状态并结束待办）
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean completeSign(String taskId, Long signOssId) {
        SysFlowTask task = flowService.getTaskById(taskId);
        if (task == null) {
            throw new ServiceException("任务不存在");
        }
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser != null && !task.getApproverId().equals(String.valueOf(loginUser.getBusinessUserId()))) {
            throw new ServiceException("无权操作此任务");
        }
        SysFlowInstance instance = flowService.getInstanceByTaskId(taskId);
        if (instance == null) {
            throw new ServiceException("流程实例不存在");
        }
        Long detailId;
        try {
            detailId = Long.valueOf(instance.getBusinessId());
        } catch (NumberFormatException e) {
            throw new ServiceException("业务数据异常");
        }
        HotSignFileDetail detail = baseMapper.selectById(detailId);
        if (detail == null) {
            throw new ServiceException("文件记录不存在");
        }
        if (DriverLoginContextHelper.isDriverPort() && signOssId != null) {
            if (StringUtils.isBlank(detail.getStaffName())) {
                throw new ServiceException("签署人姓名不能为空");
            }
            signatureVerifyService.validateSelfSignature(signOssId, detail.getStaffName());
        }
        detail.setSignStatus(1L);
        detail.setSignTime(new Date());
        detail.setSignOssId(String.valueOf(signOssId));
        // 计算并设置到期时间
        HotNoticeSignDocumentVo documentVo = documentService.queryById(detail.getIssueFileId());
        if (documentVo != null && documentVo.getValidType() != null) {
            Long validType = documentVo.getValidType();
            String validPeriod = documentVo.getValidPeriod();
            try {
                if (Long.valueOf(0L).equals(validType)) {
                    // 短期：validPeriod 是具体日期字符串（YYYY-MM-DD）
                    if (validPeriod != null) {
                        LocalDate date = LocalDate.parse(validPeriod, DateTimeFormatter.ISO_LOCAL_DATE);
                        detail.setExpireTime(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()));
                    }
                } else if (Long.valueOf(1L).equals(validType)) {
                    // 定期：validPeriod 是月份数
                    long months = 0L;
                    if (validPeriod != null) {
                        months = Long.parseLong(validPeriod);
                    }
                    LocalDate date = LocalDate.now().plusMonths(months);
                    detail.setExpireTime(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()));
                }
                // 长期（2）或其他，不设置到期时间
            } catch (Exception e) {
                // 忽略解析异常，避免影响签署流程
                log.warn("设置到期时间失败：{}", e.getMessage());
            }
        }

        baseMapper.updateById(detail);
        flowService.audit(taskId, true, "签署完成", task.getApproverId());
        return true;
    }
}
