package com.zt.plat.module.erp.service.erp;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.zt.plat.module.api.BaseApi;
import com.zt.plat.module.api.dto.AccountDTO;
import com.zt.plat.module.api.dto.ElementDTO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpCompanyPageReqVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpCompanyRespVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpCompanySaveReqVO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpCompanyDO;
import com.zt.plat.module.erp.dal.mysql.erp.ErpCompanyMapper;
import com.zt.plat.module.erp.enums.OftenEnum;
import com.zt.plat.module.erp.utils.ErpConfig;
import com.zt.plat.module.erp.utils.MyRedisConfig;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.erp.enums.ApiConstants.TABLE_FIELD_SPLY_ERP_CPN_NUM;
import static com.zt.plat.module.erp.enums.ErrorCodeConstants.ERP_COMPANY_NOT_EXISTS;

/**
 * ERP公司 Service 实现类
 *
 * @author 后台管理
 */
@Service
@Validated
public class ErpCompanyServiceImpl implements ErpCompanyService {

    @Resource
    private ErpCompanyMapper erpCompanyMapper;
    @Resource
    private MyRedisConfig myRedisConfig;
    @Resource
    private ErpConfig erpConfig;
    @Value("${erp.address}")
    private String erpAddress;
    @Value("${erp.sapsys}")
    private String sapsys;
    @Resource
    private BaseApi baseApi;

    @Override
    public ErpCompanyRespVO createErpCompany(ErpCompanySaveReqVO createReqVO) {
        // 插入
        ErpCompanyDO erpCompany = BeanUtils.toBean(createReqVO, ErpCompanyDO.class);
        erpCompanyMapper.insert(erpCompany);
        // 返回
        return BeanUtils.toBean(erpCompany, ErpCompanyRespVO.class);
    }

    @Override
    public void updateErpCompany(ErpCompanySaveReqVO updateReqVO) {
        // 校验存在
        validateErpCompanyExists(updateReqVO.getId());
        // 更新
        ErpCompanyDO updateObj = BeanUtils.toBean(updateReqVO, ErpCompanyDO.class);
        erpCompanyMapper.updateById(updateObj);
    }

    @Override
    public void deleteErpCompany(Long id) {
        // 校验存在
        validateErpCompanyExists(id);
        // 删除
        erpCompanyMapper.deleteById(id);
    }

    @Override
    public void deleteErpCompanyListByIds(List<Long> ids) {
        // 校验存在
        validateErpCompanyExists(ids);
        // 删除
        erpCompanyMapper.deleteByIds(ids);
    }

    private void validateErpCompanyExists(List<Long> ids) {
        List<ErpCompanyDO> list = erpCompanyMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(ERP_COMPANY_NOT_EXISTS);
        }
    }

    private void validateErpCompanyExists(Long id) {
        if (erpCompanyMapper.selectById(id) == null) {
            throw exception(ERP_COMPANY_NOT_EXISTS);
        }
    }

    @Override
    public ErpCompanyDO getErpCompany(Long id) {
        return erpCompanyMapper.selectById(id);
    }

    @Override
    public PageResult<ErpCompanyDO> getErpCompanyPage(ErpCompanyPageReqVO pageReqVO) {
        return erpCompanyMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional
    @XxlJob("getCompanyTask")
    public void callErpRfcInterface() {
        OftenEnum.FuncnrEnum funcnrEnum = OftenEnum.FuncnrEnum.公司代码;
        String funcnr = funcnrEnum.getFuncnr();
        //防止缓存数据丢失
        String key = "erpMap" + funcnrEnum.getFuncnr();
        if (myRedisConfig.getRedisCacheMap(key).isEmpty()) {
            initializeMap(key);
        }
        // 1. 调用ERP接口获取数据
        Map<String, Object> dataFromERP = erpConfig.fetchDataFromERP(funcnr, null);
        JSONArray dataArray = (JSONArray) dataFromERP.get("E_RESP");
        if (CollUtil.isEmpty(dataArray)) {
            throw exception(ERP_COMPANY_NOT_EXISTS);
        }

        // 2. 处理公司数据，区分新增和更新
        ProcessingResult result = processData(dataArray, funcnrEnum);

        // 3. 批量保存数据
        saveData(result);
    }

    @Override
    public ErpCompanyDO getErpCompanyByNumber(String number) {
        return erpCompanyMapper.selectOne(TABLE_FIELD_SPLY_ERP_CPN_NUM, number);
    }

    /**
     * 处理数据，区分新增和更新
     */
    private ProcessingResult processData(JSONArray dataArray, OftenEnum.FuncnrEnum funcnr) {
        String key = "erpMap" + funcnr.getFuncnr();
        Map<String, Long> numbers = myRedisConfig.getRedisCacheMap(key);
        List<ErpCompanyDO> toUpdate = new ArrayList<>();
        List<ErpCompanyDO> toInsert = new ArrayList<>();

        List<String> dataArrayNumbers = new ArrayList<>();
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataJson = dataArray.getJSONObject(i);
            if (dataJson != null) {
                String number = dataJson.getString("BUKRS").trim();
                ErpCompanyDO DO = new ErpCompanyDO();
                DO.setName(dataJson.getString("BUTXT"));
                DO.setNumber(number);
                DO.setCurrency(dataJson.getString("WAERS"));
                if (numbers.get(number) != null) {
                    // 更新
                    DO.setId(numbers.get(number));
                    toUpdate.add(DO);
                } else {
                    // 新增
                    toInsert.add(DO);
                }
                dataArrayNumbers.add(number);
            }
        }

        // 过滤出numbers中有，但dataArray中KOSTL没有的记录，即为需要删除的数据
        List<String> deleteNumbers = new ArrayList<>();
        for (String number : numbers.keySet()) {
            if (!dataArrayNumbers.contains(number)) {
                deleteNumbers.add(number);
            }
        }
        return new ProcessingResult(toUpdate, toInsert, deleteNumbers, key);
    }

    /**
     * 批量保存数据
     */
    private void saveData(ProcessingResult result) {
        // 批量新增和更新
        if (!result.toInsert.isEmpty()) {
            erpCompanyMapper.insertBatch(result.toInsert);
            // 批量查询刚插入数据的id，提升效率
            List<String> insertedNumbers = result.toInsert.stream()
                    .map(ErpCompanyDO::getNumber)
                    .collect(Collectors.toList());
            List<ErpCompanyDO> insertedRecords = erpCompanyMapper.selectList(
                    new LambdaQueryWrapperX<ErpCompanyDO>()
                            .in(ErpCompanyDO::getNumber, insertedNumbers)
            );
            Map<String, Long> numberIdMap = insertedRecords.stream()
                    .collect(Collectors.toMap(ErpCompanyDO::getNumber, ErpCompanyDO::getId));
            myRedisConfig.addRedisCacheMap(result.key, numberIdMap);
        }
        if (!result.toUpdate.isEmpty()) {
            erpCompanyMapper.updateBatch(result.toUpdate);
        }
        if (!result.deleteNumbers.isEmpty()) {
            // 使用 in 条件批量删除，提高删除效率
            erpCompanyMapper.delete(new LambdaQueryWrapperX<ErpCompanyDO>().in(ErpCompanyDO::getNumber, result.deleteNumbers));
            myRedisConfig.deleteRedisCacheMap(result.key, result.deleteNumbers);
        }
    }

    /**
     * 数据处理结果封装类
     */
    private static class ProcessingResult {
        private final List<ErpCompanyDO> toUpdate;
        private final List<ErpCompanyDO> toInsert;
        private final List<String> deleteNumbers;
        private final String key;


        public ProcessingResult(List<ErpCompanyDO> toUpdate, List<ErpCompanyDO> toInsert, List<String> deleteNumbers, String key) {
            this.toUpdate = toUpdate;
            this.toInsert = toInsert;
            this.deleteNumbers = deleteNumbers;
            this.key = key;
        }
    }

    private void initializeMap(String key) {
        Map<String, Long> existingNumbers = erpCompanyMapper.selectList(new LambdaQueryWrapperX<ErpCompanyDO>())
                .stream()
                .collect(Collectors.toMap(ErpCompanyDO::getNumber, ErpCompanyDO::getId));
        myRedisConfig.addRedisCacheMap(key, existingNumbers);
    }

    @Override
    public void test() {
        OftenEnum.FuncnrEnum funcnrEnum = OftenEnum.FuncnrEnum.公司代码;
        String funcnr = funcnrEnum.getFuncnr();
        //防止缓存数据丢失
        String key = "erpMap" + funcnrEnum.getFuncnr();
        myRedisConfig.getRedisCacheMap(key);
        // 1. 调用ERP接口获取数据
        Map<String, Object> dataFromERP = erpConfig.fetchDataFromERP(funcnr, null);
        JSONArray dataArray = (JSONArray) dataFromERP.get("E_RESP");
        if (CollUtil.isEmpty(dataArray)) {
            throw exception(ERP_COMPANY_NOT_EXISTS);
        }
    }

    @Override
    public String test1() {
        String address = erpAddress + "-" + sapsys;
        OftenEnum.FuncnrEnum funcnrEnum = OftenEnum.FuncnrEnum.公司代码;
        String funcnr = funcnrEnum.getFuncnr();

        // 构建完整URL
        String url = "http://" + erpAddress + "/api/rfc/get";
        // 构建请求参数
        JSONObject requestBody = new JSONObject();
        requestBody.put("sapsys", sapsys);
        requestBody.put("funcnr", funcnr); // 获取枚举值

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.valueOf(MediaType.APPLICATION_JSON_UTF8_VALUE));

        // 创建HTTP请求实体
        HttpEntity<String> requestEntity = new HttpEntity<>(requestBody.toJSONString(), headers);
        // 发送POST请求
        RestTemplate restTemplate = new RestTemplate();
        try {
            ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
            return url + requestEntity + response;
        } catch (Exception e) {
            return url + requestEntity;
        }
    }
}