package com.usky.vpp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.usky.common.core.bean.CommonPage;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.vpp.domain.VppContract;
import com.usky.vpp.domain.VppContractTemplate;
import com.usky.vpp.mapper.VppContractMapper;
import com.usky.vpp.mapper.VppContractTemplateMapper;
import com.usky.vpp.service.VppContractTemplateService;
import com.usky.vpp.service.vo.VppContractTemplateRequestVO;
import com.usky.vpp.service.vo.VppContractTemplateResponseVO;
import com.usky.vpp.util.VppFieldValidator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * VppContractTemplateService 默认实现
 * @author fyc
 * @email yuchuan.fu@chinausky.com
 * @date 2026/7/4
 */
@Service
public class VppContractTemplateServiceImpl implements VppContractTemplateService {

    @Autowired
    private VppContractTemplateMapper vppContractTemplateMapper;
    @Autowired
    private VppContractMapper vppContractMapper;

    private final RestTemplate restTemplate = new RestTemplate();

    @Override
    public Boolean create(VppContractTemplateRequestVO vo) {
        String username = SecurityUtils.getUsername();
        Integer tenantId = SecurityUtils.getTenantId();

        // ========== templateCode 格式校验 ==========
        VppFieldValidator.validateTemplateCode(vo.getTemplateCode());

        // ========== templateCode 全租户唯一性校验 ==========
        checkTemplateCodeUnique(vo.getTemplateCode(), null, tenantId);
        if (vo.getTemplateKind() != null && vo.getTemplateKind() != 1 && vo.getTemplateKind() != 2) {
            throw new BusinessException("模板分类无效，仅支持 1居间/层间 2普通/直网！");
        }

        VppContractTemplate template = new VppContractTemplate();
        template.setTemplateCode(vo.getTemplateCode());
        template.setTemplateName(vo.getTemplateName());
        template.setContractType(vo.getContractType());
        template.setTemplateKind(vo.getTemplateKind());
        template.setVersion("V1.0");
        template.setFileUrl(vo.getFileUrl());
        template.setVariablesJson(VppFieldValidator.validateJson(vo.getVariablesJson(), "占位符变量定义"));
        template.setIsEnabled(vo.getIsEnabled() != null ? vo.getIsEnabled() : 1);
        template.setCreateTime(LocalDateTime.now());
        template.setCreatedBy(username);
        template.setTenantId(tenantId);
        template.setDeleteFlag(0);

        int insert = vppContractTemplateMapper.insert(template);
        return insert > 0;
    }

    @Override
    public Boolean update(VppContractTemplateRequestVO vo) {
        if (vo.getId() == null) {
            throw new BusinessException("主键ID不能为空！");
        }

        LambdaQueryWrapper<VppContractTemplate> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VppContractTemplate::getId, vo.getId())
                .eq(VppContractTemplate::getTenantId, SecurityUtils.getTenantId())
                .eq(VppContractTemplate::getDeleteFlag, 0);
        VppContractTemplate existingRecord = vppContractTemplateMapper.selectOne(queryWrapper);

        if (existingRecord == null) {
            throw new BusinessException("合同模板不存在或已被删除！");
        }

        // 仅更新非空字段，追踪是否仅变更 isEnabled
        boolean hasNonEnabledChange = false;

        if (StringUtils.isNotBlank(vo.getTemplateCode())) {
            // ========== templateCode 格式校验 ==========
            VppFieldValidator.validateTemplateCode(vo.getTemplateCode());

            // ========== 仅当与现有值不同时做唯一性校验 ==========
            if (!vo.getTemplateCode().equals(existingRecord.getTemplateCode())) {
                checkTemplateCodeUnique(vo.getTemplateCode(), vo.getId(), SecurityUtils.getTenantId());
            }

            existingRecord.setTemplateCode(vo.getTemplateCode());
            hasNonEnabledChange = true;
        }
        if (StringUtils.isNotBlank(vo.getTemplateName())) {
            existingRecord.setTemplateName(vo.getTemplateName());
            hasNonEnabledChange = true;
        }
        if (vo.getContractType() != null) {
            existingRecord.setContractType(vo.getContractType());
            hasNonEnabledChange = true;
        }
        if (vo.getTemplateKind() != null) {
            if (vo.getTemplateKind() != 1 && vo.getTemplateKind() != 2) {
                throw new BusinessException("模板分类无效，仅支持 1居间/层间 2普通/直网！");
            }
            existingRecord.setTemplateKind(vo.getTemplateKind());
            hasNonEnabledChange = true;
        }
        if (StringUtils.isNotBlank(vo.getFileUrl())) {
            existingRecord.setFileUrl(vo.getFileUrl());
            hasNonEnabledChange = true;
        }
        if (vo.getVariablesJson() != null) {
            existingRecord.setVariablesJson(VppFieldValidator.validateJson(vo.getVariablesJson(), "占位符变量定义"));
            hasNonEnabledChange = true;
        }
        // isEnabled 单独变更不触发版本号累加
        if (vo.getIsEnabled() != null) {
            existingRecord.setIsEnabled(vo.getIsEnabled());
        }

        // 版本号自动累加：仅当非 isEnabled 字段有变更时 +0.1
        if (hasNonEnabledChange) {
            String currentVersion = existingRecord.getVersion();
            if (StringUtils.isNotBlank(currentVersion) && currentVersion.startsWith("V")) {
                try {
                    double versionNum = Double.parseDouble(currentVersion.substring(1));
                    versionNum += 0.1;
                    existingRecord.setVersion("V" + String.format("%.1f", versionNum));
                } catch (NumberFormatException e) {
                    existingRecord.setVersion(currentVersion + ".1");
                }
            }
        }

        existingRecord.setUpdateTime(LocalDateTime.now());
        existingRecord.setUpdatedBy(SecurityUtils.getUsername());

        int result = vppContractTemplateMapper.updateById(existingRecord);
        return result > 0;
    }

    @Override
    public CommonPage<VppContractTemplateResponseVO> page(Long id, String templateName, Integer contractType,
                                                          Integer isEnabled, Integer pageNum, Integer pageSize) {
        IPage<VppContractTemplate> page = new Page<>(pageNum, pageSize);

        LambdaQueryWrapper<VppContractTemplate> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VppContractTemplate::getDeleteFlag, 0)
                .eq(VppContractTemplate::getTenantId, SecurityUtils.getTenantId())
                .eq(id != null, VppContractTemplate::getId, id)
                .eq(contractType != null, VppContractTemplate::getContractType, contractType)
                .eq(isEnabled != null, VppContractTemplate::getIsEnabled, isEnabled)
                .like(StringUtils.isNotBlank(templateName), VppContractTemplate::getTemplateName, templateName)
                .orderByDesc(VppContractTemplate::getCreateTime);
        page = vppContractTemplateMapper.selectPage(page, queryWrapper);

        List<VppContractTemplateResponseVO> list = page.getRecords().stream().map(entity -> {
            VppContractTemplateResponseVO responseVO = new VppContractTemplateResponseVO();
            responseVO.setId(entity.getId());
            responseVO.setTemplateCode(entity.getTemplateCode());
            responseVO.setTemplateName(entity.getTemplateName());
            responseVO.setContractType(entity.getContractType());
            responseVO.setTemplateKind(entity.getTemplateKind());
            responseVO.setVersion(entity.getVersion());
            responseVO.setFileUrl(entity.getFileUrl());
            responseVO.setVariablesJson(entity.getVariablesJson());
            responseVO.setIsEnabled(entity.getIsEnabled());
            responseVO.setCreatedBy(entity.getCreatedBy());
            responseVO.setCreateTime(entity.getCreateTime());
            responseVO.setUpdatedBy(entity.getUpdatedBy());
            responseVO.setUpdateTime(entity.getUpdateTime());
            responseVO.setTenantId(entity.getTenantId());
            return responseVO;
        }).collect(Collectors.toList());

        return new CommonPage<>(list, page.getTotal(), pageSize, pageNum);
    }

    @Override
    public Boolean delete(Long id) {
        LambdaQueryWrapper<VppContractTemplate> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VppContractTemplate::getId, id)
                .eq(VppContractTemplate::getDeleteFlag, 0)
                .eq(VppContractTemplate::getTenantId, SecurityUtils.getTenantId());
        VppContractTemplate template = vppContractTemplateMapper.selectOne(queryWrapper);

        if (template == null) {
            throw new BusinessException("合同模板不存在或已被删除！");
        }

        // 模板下存在关联合同时不允许删除
        LambdaQueryWrapper<VppContract> contractWrapper = new LambdaQueryWrapper<>();
        contractWrapper.eq(VppContract::getTemplateId, id)
                .eq(VppContract::getDeleteFlag, 0);
        Integer relatedCount = vppContractMapper.selectCount(contractWrapper);
        if (relatedCount != null && relatedCount > 0) {
            throw new BusinessException("该合同模板下存在关联合同，无法删除！");
        }

        template.setDeleteFlag(1);
        template.setIsEnabled(0);
        template.setDeletedAt(LocalDateTime.now());
        template.setUpdatedBy(SecurityUtils.getUsername());
        int i = vppContractTemplateMapper.updateById(template);
        return i > 0;
    }

    @Override
    public void download(Long id, HttpServletResponse response) {
        // ========== 查询模板记录 ==========
        LambdaQueryWrapper<VppContractTemplate> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VppContractTemplate::getId, id)
                .eq(VppContractTemplate::getDeleteFlag, 0)
                .eq(VppContractTemplate::getTenantId, SecurityUtils.getTenantId());
        VppContractTemplate template = vppContractTemplateMapper.selectOne(queryWrapper);

        if (template == null) {
            writeErrorResponse(response, HttpStatus.BAD_REQUEST.value(), "合同模板不存在或已被删除！");
            return;
        }

        String fileUrl = template.getFileUrl();
        String fileName = template.getTemplateName();
        if (StringUtils.isBlank(fileUrl)) {
            writeErrorResponse(response, HttpStatus.BAD_REQUEST.value(), "模板文件URL为空，无法下载！");
            return;
        }

        // ========== 设置响应头 ==========
        // 根据 fileUrl 推断原始文件名（优先使用模板名称 + 扩展名）
        String downloadFileName = fileName;
        int dotIndex = fileUrl.lastIndexOf('.');
        if (dotIndex > 0 && !fileName.contains(".")) {
            downloadFileName = fileName + fileUrl.substring(dotIndex);
        }
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=" + encodeFileName(downloadFileName));

        // ========== 下载文件并写入响应流 ==========
        try {
            byte[] fileBytes = restTemplate.getForObject(fileUrl, byte[].class);
            if (fileBytes == null || fileBytes.length == 0) {
                writeErrorResponse(response, HttpStatus.NOT_FOUND.value(), "模板文件内容为空！");
                return;
            }
            ServletOutputStream sos = response.getOutputStream();
            sos.write(fileBytes);
            sos.flush();
        } catch (Exception e) {
            if (!response.isCommitted()) {
                writeErrorResponse(response, HttpStatus.INTERNAL_SERVER_ERROR.value(),
                        "下载合同模板失败: " + e.getMessage());
            }
        }
    }

    /**
     * 向响应中写入 JSON 错误信息
     */
    private void writeErrorResponse(HttpServletResponse response, int status, String message) {
        response.setStatus(status);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        try {
            response.getWriter().write("{\"code\":\"" + status + "\",\"msg\":\"" + message + "\"}");
        } catch (IOException e) {
            // 忽略写入异常
        }
    }

    /**
     * 编码文件名，兼容各浏览器
     */
    private String encodeFileName(String fileName) {
        try {
            return URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replace("+", "%20");
        } catch (UnsupportedEncodingException e) {
            return fileName;
        }
    }

    /**
     * 全租户唯一性校验：检查 templateCode 是否已被占用
     *
     * @param templateCode 模板编码
     * @param excludeId    排除的记录ID（更新时传入当前记录ID，创建时传 null）
     * @throws BusinessException 编码已被占用时抛出
     */
    private void checkTemplateCodeUnique(String templateCode, Long excludeId, Integer tenantId) {
        LambdaQueryWrapper<VppContractTemplate> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(VppContractTemplate::getTemplateCode, templateCode)
                .eq(VppContractTemplate::getDeleteFlag, 0)
                .eq(VppContractTemplate::getTenantId, tenantId)
                .ne(excludeId != null, VppContractTemplate::getId, excludeId);
        Integer count = vppContractTemplateMapper.selectCount(wrapper);
        if (count != null && count > 0) {
            throw new BusinessException("模板编码【" + templateCode + "】已存在，请使用其他编码！");
        }
    }
}
