package cn.iocoder.yudao.module.identity.service.scanrecord;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.identity.controller.admin.scanrecord.vo.*;
import cn.iocoder.yudao.module.identity.controller.app.scanrecord.vo.FirstScanRecordRespVO;
import cn.iocoder.yudao.module.identity.controller.app.scanrecord.vo.ScanRecordAppPageReqVO;
import cn.iocoder.yudao.module.identity.convert.scanrecord.ScanRecordConvert;
import cn.iocoder.yudao.module.identity.dal.dataobject.code.CodeDO;
import cn.iocoder.yudao.module.identity.dal.dataobject.scanrecord.ScanRecordDO;
import cn.iocoder.yudao.module.identity.dal.mysql.code.CodeMapper;
import cn.iocoder.yudao.module.identity.dal.mysql.scanrecord.ScanRecordMapper;
import cn.iocoder.yudao.module.identity.utils.CodeRequestUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.identity.enums.ErrorCodeConstants.BUSINESS_RULE_NOT_EXISTS;
import static cn.iocoder.yudao.module.identity.enums.ErrorCodeConstants.SCAN_RECORD_NOT_EXISTS;

/**
 * 扫码记录 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class ScanRecordServiceImpl implements ScanRecordService {

    @Resource
    private ScanRecordMapper scanRecordMapper;

    @Resource
    private CodeMapper codeMapper;

    /**
     * 创建扫码记录实现
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    @Override
    public Long createScanRecord(ScanRecordCreateReqVO createReqVO) {
        // 插入
        ScanRecordDO scanRecord = ScanRecordConvert.INSTANCE.convert(createReqVO);
        scanRecordMapper.insert(scanRecord);
        // 返回
        return scanRecord.getId();
    }

    @Override
    @Transactional
    public void createBatchScanRecord(CreateFirstScanRecordReqVO params) {
        // 查询批次对应的所有二维码编码
        List<CodeDO> allCodeList = codeMapper.getListByBatchIds(params.getBatchIdList());
        Map<String, List<CodeDO>> codeListMap = CollectionUtils.convertMultiMap(allCodeList, CodeDO::getBatchId);

        List<ScanRecordDO> createList = new ArrayList<>();
        params.getBatchIdList().forEach(batchId -> {
            List<CodeDO> codeList = codeListMap.get(batchId);

            codeList.forEach(code -> {
                ScanRecordDO scanRecordDO = new ScanRecordDO();
                scanRecordDO.setGenerateRecordId(code.getGenerateRecordId());
                scanRecordDO.setIdentityUrl(code.getIdentityCode());
                scanRecordDO.setBatchId(code.getBatchId());
                scanRecordDO.setGoodsId(code.getGoodsId());
                scanRecordDO.setGoodsName(code.getGoodsName());
                scanRecordDO.setScanIp(params.getScanIp());
                scanRecordDO.setBatchType((byte) 0);
                scanRecordDO.setScanArea(params.getScanArea());
                scanRecordDO.setScanLocation(params.getScanLocation());
                scanRecordDO.setScanTime(params.getScanTime());
                scanRecordDO.setBrokenResult("{\"id\":87,\"break_status\":{\"key\":\"UNBROKEN\",\"value\":0,\"description\":\"未打开\",\"remark\":\"批量\"}}");
                scanRecordDO.setMobileSystemInfo("{\"type\":\"h5\",\"userAgent\":\"Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Mobile/15E148 Safari/604.1\",\"model\":\"iPhone\",\"brand\":\"iPhone\",\"platform\":\"iOS\",\"system\":\"iOS 18.1\"}");
                scanRecordDO.setBelongBusinessId(code.getBelongBusinessId());
                scanRecordDO.setBelongBusinessName(code.getBelongBusinessName());

                createList.add(scanRecordDO);
            });
        });

        if (!createList.isEmpty()) {
            scanRecordMapper.insertBatch(createList);
        }
    }

    /**
     * 更新扫码记录实现
     *
     * @param updateReqVO 更新信息
     */
    @Override
    public void updateScanRecord(ScanRecordUpdateReqVO updateReqVO) {
        // 校验存在
        validateScanRecordExists(updateReqVO.getId());
        // 更新
        ScanRecordDO updateObj = ScanRecordConvert.INSTANCE.convert(updateReqVO);
        scanRecordMapper.updateById(updateObj);
    }

    /**
     * 删除扫码记录实现
     *
     * @param id 编号
     */
    @Override
    public void deleteScanRecord(Long id) {
        // 校验存在
        validateScanRecordExists(id);
        // 删除
        scanRecordMapper.deleteById(id);
    }

    private void validateScanRecordExists(Long id) {
        if (scanRecordMapper.selectById(id) == null) {
            throw exception(SCAN_RECORD_NOT_EXISTS);
        }
    }

    /**
     * 获得扫码记录实现
     *
     * @param id 编号
     * @return 扫码记录
     */
    @Override
    public ScanRecordDO getScanRecord(Long id) {
        return scanRecordMapper.selectById(id);
    }

    /**
     * 获得扫码记录列表实现
     *
     * @param ids 编号
     * @return 扫码记录列表
     */
    @Override
    public List<ScanRecordDO> getScanRecordList(Collection<Long> ids) {
        return scanRecordMapper.selectBatchIds(ids);
    }

    /**
     * 获得扫码记录分页实现
     *
     * @param pageReqVO 分页查询
     * @return 扫码记录分页
     */
    @Override
    public PageResult<ScanRecordDO> getScanRecordPage(ScanRecordPageReqVO pageReqVO) {
        return scanRecordMapper.selectPage(pageReqVO);
    }

    /**
     * 获得扫码记录列表, 用于 Excel 导出实现
     *
     * @param exportReqVO 查询条件
     * @return 扫码记录列表
     */
    @Override
    public List<ScanRecordDO> getScanRecordList(ScanRecordExportReqVO exportReqVO) {
        return scanRecordMapper.selectList(exportReqVO);
    }

    /**
     * 获得扫码次数
     *
     * @param goodsName
     * @param belongBusinessName
     * @param timeHorizon1
     * @param timeHorizon2
     */
    @Override
    public int getScanRecordCount(String goodsName, String belongBusinessName, String timeHorizon1, String timeHorizon2) {
        //创建map对象
        LambdaQueryWrapper<ScanRecordDO> wrapper = new LambdaQueryWrapper<>();
        // 添加查询条件，商户名称
        wrapper.eq(ScanRecordDO::getBelongBusinessName, belongBusinessName);
        // 添加查询条件，商品名称
        wrapper.eq(ScanRecordDO::getGoodsName, goodsName);
        //时间转换
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date startDate = sdf.parse(timeHorizon1);
            Date endDate = sdf.parse(timeHorizon2);
            // 添加查询条件，扫码时间在时间范围内
            wrapper.between(ScanRecordDO::getScanTime, startDate, endDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //获取所有
        List<ScanRecordDO> scanRecordList = scanRecordMapper.selectList(wrapper);
        // 统计扫码次数
        int scanCount = scanRecordList.size();
        return scanCount;
    }

    /**
     * 根据查询时间范围条件，查询出每日的查询次数
     *
     * @param goodsName
     * @param belongBusinessName
     * @param timeHorizon1
     * @param timeHorizon2
     * @return
     */
    @Override
    public Map<String, Long> getScanCountByDay(String goodsName, String belongBusinessName, String timeHorizon1, String timeHorizon2) {
        //创建map对象
        Map<String, Long> scanCountMap = new HashMap<>();
        // 将时间范围转换为Date类型
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date startDate = sdf.parse(timeHorizon1);
            Date endDate = sdf.parse(timeHorizon2);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            // 分组统计扫码次数
            while (!calendar.getTime().after(endDate)) {
                String scanDate = sdf.format(calendar.getTime());
                String startTime = scanDate + " 00:00:00";
                String endTime = scanDate + " 23:59:59";
                // 构造结果Map
                int scanRecordListTist = getScanRecordCount(goodsName, belongBusinessName, startTime, endTime);
                scanCountMap.put(scanDate, (long) scanRecordListTist);
                calendar.add(Calendar.DATE, 1);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //返回
        return scanCountMap;

    }

    /**
     * 根据商户名称、商品和时间范围统计商户地区
     *
     * @param goodsName    商品名称
     * @param businessName 商户名称
     * @param timeHorizon1 开始时间
     * @param timeHorizon2 结束时间
     * @return 商户地区列表
     */
    @Override
    public List<String> getBusinessRegionList(Long businessName, Long goodsName, String timeHorizon1, String timeHorizon2) {
        //创建map对象
        LambdaQueryWrapper<ScanRecordDO> wrapper = new LambdaQueryWrapper<>();
        // 添加查询条件，商户ID等于businessName
        wrapper.eq(ScanRecordDO::getBelongBusinessId, businessName);
        // 添加查询条件，商品ID等于goodsName
        wrapper.eq(ScanRecordDO::getGoodsId, goodsName);
        //时间转换
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            // 将开始时间和结束时间转换成Date类型
            Date date1 = sdf.parse(timeHorizon1);
            Date date2 = sdf.parse(timeHorizon2);
            // 添加查询条件，扫码时间在时间范围内
            wrapper.between(ScanRecordDO::getScanTime, date1, date2);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        // 设置查询的列，只查询商户地区列
//        wrapper.select(ScanRecordDO::getScanArea);
        // 去重查询，并返回商户地区列表
        List<String> businessRegionList = scanRecordMapper
                .selectList(wrapper)
                .stream()
                .distinct()
                .map(ScanRecordDO::getScanArea).collect(Collectors.toList());
        return businessRegionList;
    }

    @Override
    public List<ScanRecordDO> getRecordListForApp(String identityCode) {
        // 默认只查询最新30条记录
        return scanRecordMapper.selectList(new LambdaQueryWrapper<ScanRecordDO>().eq(ScanRecordDO::getIdentityUrl, identityCode)
                .orderByDesc(ScanRecordDO::getScanTime).last(" limit 30"));
    }

    @Override
    public PageResult<ScanRecordDO> getRecordPageForApp(ScanRecordAppPageReqVO reqVO) {
        return scanRecordMapper.selectPage(reqVO, new LambdaQueryWrapperX<ScanRecordDO>()
                .eq(ScanRecordDO::getIdentityUrl, reqVO.getIdentityCode())
                .orderByDesc(ScanRecordDO::getScanTime));
    }

    @Override
    @Transactional
    public void createByApp(String identityCode, String scanIp, String region, String type, String m, String mobileSystemInfo) {
        // 根据标识码内容查询标识码
        CodeDO codeDO = codeMapper.selectOne(new LambdaQueryWrapper<CodeDO>().eq(CodeDO::getIdentityCode, identityCode));
        if (codeDO == null) {
            throw ServiceExceptionUtil.exception(BUSINESS_RULE_NOT_EXISTS);
        }
        String scanArea;
        String scanLocation;
        if (region == null) {
            scanArea = "未知区域";
            scanLocation = "未知地点";
        } else {
            int countryIndex = region.indexOf("|");
            if (countryIndex != -1) {
                scanArea = region.substring(0, countryIndex); // 国家
                int lastIndex = region.lastIndexOf("|");

                scanLocation = region.substring(countryIndex + 1, lastIndex).replaceAll("0\\|", "").replaceAll("\\|", " ");
            } else {
                scanArea = region;
                scanLocation = "未知地点";
            }
        }

        // 扫码地址与经销商的销售区域相同，仅新增扫码记录
        Date now = new Date();
        LocalDateTime localDateTime = now.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        ScanRecordDO scanRecordDO = new ScanRecordDO();
        BeanUtil.copyProperties(codeDO, scanRecordDO);
        scanRecordDO.setId(null);
        scanRecordDO.setIdentityUrl(identityCode);
        scanRecordDO.setScanIp(scanIp);
        scanRecordDO.setScanArea(scanArea);
        scanRecordDO.setScanLocation(scanLocation);
        scanRecordDO.setScanTime(now);
        scanRecordDO.setMobileSystemInfo(mobileSystemInfo);
        scanRecordDO.setCreateTime(localDateTime);
        scanRecordDO.setUpdateTime(localDateTime);

        if (StringUtils.isNotBlank(type) && StringUtils.isNotBlank(m)) {
            log.info("查询标签是否断开入参 type: {}, m: {}", type, m);
            BrokenRespVO broken = this.isBroken(type, m);
            scanRecordDO.setBrokenResult(new JSONObject(broken).toString());
        }

        scanRecordMapper.insert(scanRecordDO);
    }

    /**
     * 根据identityUrl 获取首次的扫码时间与首次扫码地点
     *
     * @param identityUrl
     * @return
     */
    @Override
    public ScanRecordDO getFirstScanInfoByUrl(String identityUrl) {
        // 提取identityUrl的值
        String extractedIdentityUrl = extractIdentityUrl(identityUrl);
        // 查询指定identityUrl的所有扫码记录
//        QueryWrapper<ScanRecordDO> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("identity_url", extractedIdentityUrl);
//        List<ScanRecordDO> scanRecords = scanRecordMapper.selectList(queryWrapper);
//
//        // 如果找到了扫码记录
//        if (!scanRecords.isEmpty()) {
//            // 初始化首次扫码时间与扫码地点为第一条记录的值
//            Date firstScanTime = scanRecords.get(0).getScanTime();
//            String firstScanLocation = scanRecords.get(0).getScanLocation();
//
//            // 遍历扫码记录，找到首次扫码时间与扫码地点
//            for (ScanRecordDO scanRecord : scanRecords) {
//                Date scanTime = scanRecord.getScanTime();
//                String scanLocation = scanRecord.getScanLocation();
//
//                // 如果当前扫码时间早于首次扫码时间，则更新首次扫码时间与扫码地点
//                if (scanTime.before(firstScanTime)) {
//                    firstScanTime = scanTime;
//                    firstScanLocation = scanLocation;
//                }
//            }
//
//            // 构建ScanRecordDO对象，保存首次扫码时间与首次扫码地点
//            ScanRecordDO scanInfo = new ScanRecordDO();
//            scanInfo.setScanTime(firstScanTime);
//            scanInfo.setScanLocation(firstScanLocation);
//            return scanInfo;
//        } else {
//            return null; // 没有找到对应的扫码记录
//        }
        return scanRecordMapper.selectOne(new LambdaQueryWrapperX<ScanRecordDO>().eq(ScanRecordDO::getIdentityUrl, extractedIdentityUrl)
                .orderByDesc(ScanRecordDO::getScanTime).last("limit 1"));
    }

    /**
     * 从URL中提取identityUrl的值
     *
     * @param url 完整的URL地址
     * @return 提取出的identityUrl值
     */
    private String extractIdentityUrl(String url) {
        // 解析URL，提取参数id的值
        String[] split = url.split("\\?id=");
        if (split.length > 1) {
            return split[1];
        } else {
            return "";
        }
    }

    /**
     * 根据identityUrl 获取首次的扫码时间与首次扫码地点和扫码次数
     *
     * @param identityUrl
     * @return
     */
    @Override
    public FirstScanRecordRespVO getFirstScanInfoByUrlAndNumber(String identityUrl) {
        // 提取identityUrl的值
        String extractedIdentityUrl = extractIdentityUrl(identityUrl);
        FirstScanRecordRespVO result = new FirstScanRecordRespVO();
        ScanRecordDO scanRecord = scanRecordMapper.selectOne(new LambdaQueryWrapperX<ScanRecordDO>().eq(ScanRecordDO::getIdentityUrl, extractedIdentityUrl)
                .orderByAsc(ScanRecordDO::getScanTime).last("limit 1"));
        if (scanRecord == null) {
            return null;
        }
        Long total = scanRecordMapper.selectCount(new LambdaQueryWrapperX<ScanRecordDO>().eq(ScanRecordDO::getIdentityUrl, extractedIdentityUrl));
        BeanUtil.copyProperties(scanRecord, result);
        result.setTotal(total);
        return result;
    }

    @Override
    public List<ScanRecordDO> getScanLocationAndTimeByUrl(String identityUrl) {
        // 提取identityUrl的值
        String extractedIdentityUrl = extractIdentityUrl(identityUrl);
        return scanRecordMapper.selectList(new LambdaQueryWrapperX<ScanRecordDO>().eq(ScanRecordDO::getIdentityUrl, extractedIdentityUrl)
                .orderByDesc(ScanRecordDO::getScanTime).last(" limit 10"));
    }

    @Override
    public ScanRecordDO getFirstScanInfoByBatchId(String batchId) {
//        // 查询指定identityUrl的所有扫码记录
//        QueryWrapper<ScanRecordDO> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("batch_id", batchId);
//        List<ScanRecordDO> scanRecords = scanRecordMapper.selectList(queryWrapper);
//
//        // 如果找到了扫码记录
//        if (!scanRecords.isEmpty()) {
//            // 初始化首次扫码时间、扫码地点和识别次数为第一条记录的值
//            Date firstScanTime = scanRecords.get(0).getScanTime();
//            String firstScanLocation = scanRecords.get(0).getScanLocation();
//
//
//            // 遍历扫码记录，找到首次扫码时间、扫码地点和计算识别次数
//            for (ScanRecordDO scanRecord : scanRecords) {
//                Date scanTime = scanRecord.getScanTime();
//                String scanLocation = scanRecord.getScanLocation();
//
//                // 如果当前扫码时间早于首次扫码时间，则更新首次扫码时间和扫码地点
//                if (scanTime.before(firstScanTime)) {
//                    firstScanTime = scanTime;
//                    firstScanLocation = scanLocation;
//                }
//
//            }
//
//            // 构建ScanRecordDO对象，保存首次扫码时间、扫码地点和识别次数
//            ScanRecordDO scanInfo = new ScanRecordDO();
//            scanInfo.setScanTime(firstScanTime);
//            scanInfo.setScanLocation(firstScanLocation);
//            return scanInfo;
//        } else {
//            return null; // 没有找到对应的扫码记录
//        }
        return scanRecordMapper.selectOne(new LambdaQueryWrapperX<ScanRecordDO>().eq(ScanRecordDO::getBatchId, batchId)
                .orderByDesc(ScanRecordDO::getScanTime).last("limit 1"));
    }

    /**
     * 根据identityUrl APP获取首次的扫码时间与首次扫码地点
     *
     * @param identityUrl
     * @return
     */
    @Override
    public ScanRecordDO getFirstScanInfoByUrlApp(String identityUrl) {
        // 查询指定identityUrl的所有扫码记录
        QueryWrapper<ScanRecordDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("identity_url", identityUrl);
        List<ScanRecordDO> scanRecords = scanRecordMapper.selectList(queryWrapper);

        // 如果找到了扫码记录
        if (!scanRecords.isEmpty()) {
            // 初始化首次扫码时间与扫码地点为第一条记录的值
            Date firstScanTime = scanRecords.get(0).getScanTime();
            String firstScanLocation = scanRecords.get(0).getScanLocation();

            // 遍历扫码记录，找到首次扫码时间与扫码地点
            for (ScanRecordDO scanRecord : scanRecords) {
                Date scanTime = scanRecord.getScanTime();
                String scanLocation = scanRecord.getScanLocation();

                // 如果当前扫码时间早于首次扫码时间，则更新首次扫码时间与扫码地点
                if (scanTime.before(firstScanTime)) {
                    firstScanTime = scanTime;
                    firstScanLocation = scanLocation;
                }
            }

            // 构建ScanRecordDO对象，保存首次扫码时间与首次扫码地点
            ScanRecordDO scanInfo = new ScanRecordDO();
            scanInfo.setScanTime(firstScanTime);
            scanInfo.setScanLocation(firstScanLocation);
            return scanInfo;
        } else {
            // 没有找到对应的扫码记录
            return null;
        }
    }

    @Override
    public FirstScanRecordRespVO getLastScanInfoByUrl(String identityUrl) {
        FirstScanRecordRespVO result = new FirstScanRecordRespVO();
        ScanRecordDO last = scanRecordMapper.selectOne(new LambdaQueryWrapperX<ScanRecordDO>().eq(ScanRecordDO::getIdentityUrl, identityUrl)
                .orderByDesc(ScanRecordDO::getScanTime).last("LIMIT 1"));
        Long count = scanRecordMapper.selectCount(new LambdaQueryWrapperX<ScanRecordDO>().eq(ScanRecordDO::getIdentityUrl, identityUrl));
        if (last == null) {
            return result;
        }
        BeanUtil.copyProperties(last, result);
        result.setTotal(count);
        return result;
    }

    @Override
    public BrokenRespVO isBroken(String type, String m) {
        Map<String, String> params = new HashMap<>();
        params.put("type", type);
        params.put("m", m);
        String result = CodeRequestUtils.httpPOST(new JSONObject(params).toString(), CodeRequestUtils.PRIVATE_KEY);
        String data = new JSONObject(result).getStr("data");
        return new JSONObject(data).toBean(BrokenRespVO.class);
    }

}
