package com.sckw.system.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.sckw.core.model.page.PageResult;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.system.model.KwsEnterprise;
import com.sckw.system.model.KwsWeighbridge;
import com.sckw.system.model.KwsWeighbridgeRecord;
import com.sckw.system.model.ValidateLicensePlate;
import com.sckw.system.model.report.WeighbridgeRecordExcel;
import com.sckw.system.model.vo.req.LicensePlateValidateRequest;
import com.sckw.system.model.vo.req.WeighbridgePushRequest;
import com.sckw.system.model.vo.req.WeighbridgeRecordPageReqVo;
import com.sckw.system.model.vo.res.LicensePlateValidateResponse;
import com.sckw.system.model.vo.res.WeighbridgeRecordResVo;
import com.sckw.system.repository.KwsEnterpriseRepository;
import com.sckw.system.repository.KwsWeighbridgeRecordRepository;
import com.sckw.system.repository.KwsWeighbridgeRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 地磅称重记录业务服务。
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class KwsWeighbridgeRecordManageService {

    private final KwsWeighbridgeRecordRepository kwsWeighbridgeRecordRepository;
    private final KwsWeighbridgeRepository kwsWeighbridgeRepository;
    private final KwsEnterpriseRepository kwsEnterpriseRepository;
    private final ValidateLicensePlateService validateLicensePlateService;

    public PageResult page(WeighbridgeRecordPageReqVo reqVo) {
        Set<Long> weighbridgeIds = resolveWeighbridgeIds(reqVo);
        if (weighbridgeIds.isEmpty()) {
            return PageResult.build(reqVo.getPage(), reqVo.getPageSize(), 0L, Collections.emptyList());
        }
        IPage<KwsWeighbridgeRecord> page = kwsWeighbridgeRecordRepository.pageQuery(reqVo.getPage(), reqVo.getPageSize(),
                weighbridgeIds, reqVo.getTruckNo(), reqVo.getMinWeight(), reqVo.getMaxWeight(),
                reqVo.getCreateStartTime(), reqVo.getCreateEndTime(), reqVo.getReceiveStartTime(), reqVo.getReceiveEndTime());
        return PageResult.of(page, buildRes(page.getRecords()));
    }

    public List<WeighbridgeRecordExcel> exportList(WeighbridgeRecordPageReqVo reqVo) {
        Set<Long> weighbridgeIds = resolveWeighbridgeIds(reqVo);
        if (weighbridgeIds.isEmpty()) {
            return Collections.emptyList();
        }
        List<KwsWeighbridgeRecord> records = kwsWeighbridgeRecordRepository.listQuery(weighbridgeIds, reqVo.getTruckNo(),
                reqVo.getMinWeight(), reqVo.getMaxWeight(), reqVo.getCreateStartTime(), reqVo.getCreateEndTime(),
                reqVo.getReceiveStartTime(), reqVo.getReceiveEndTime());
        return buildExportRows(buildRes(records));
    }

    private List<WeighbridgeRecordResVo> buildRes(List<KwsWeighbridgeRecord> records) {
        if (records == null || records.isEmpty()) {
            return Collections.emptyList();
        }
        Map<Long, KwsWeighbridge> weighbridgeMap = weighbridgeMap(records.stream()
                .map(KwsWeighbridgeRecord::getWeighbridgeId).collect(Collectors.toSet()));
        Map<Long, String> entNameMap = enterpriseNameMap(weighbridgeMap.values().stream()
                .map(KwsWeighbridge::getEntId).collect(Collectors.toSet()));
        List<WeighbridgeRecordResVo> result = new ArrayList<>(records.size());
        for (KwsWeighbridgeRecord record : records) {
            KwsWeighbridge weighbridge = weighbridgeMap.get(record.getWeighbridgeId());
            WeighbridgeRecordResVo resVo = new WeighbridgeRecordResVo();
            resVo.setId(record.getId());
            resVo.setWeighbridgeId(record.getWeighbridgeId());
            resVo.setWeighbridgeName(weighbridge == null ? "" : weighbridge.getWeighbridgeName());
            resVo.setUniqueCode(weighbridge == null ? "" : weighbridge.getUniqueCode());
            resVo.setEntId(weighbridge == null ? null : weighbridge.getEntId());
            resVo.setEnterpriseName(weighbridge == null ? "" : entNameMap.getOrDefault(weighbridge.getEntId(), ""));
            resVo.setTruckNo(record.getTruckNo());
            resVo.setWeight(record.getWeight());
            resVo.setCreateTime(record.getCreateTime());
            resVo.setReceiveTime(record.getReceiveTime());
            result.add(resVo);
        }
        return result;
    }

    private List<WeighbridgeRecordExcel> buildExportRows(List<WeighbridgeRecordResVo> rows) {
        if (rows == null || rows.isEmpty()) {
            return Collections.emptyList();
        }
        List<WeighbridgeRecordExcel> result = new ArrayList<>(rows.size());
        for (WeighbridgeRecordResVo row : rows) {
            WeighbridgeRecordExcel excel = new WeighbridgeRecordExcel();
            excel.setWeighbridgeName(row.getWeighbridgeName());
            excel.setUniqueCode(row.getUniqueCode());
            excel.setEnterpriseName(row.getEnterpriseName());
            excel.setTruckNo(row.getTruckNo());
            excel.setWeight(row.getWeight());
            excel.setCreateTime(row.getCreateTime());
            excel.setReceiveTime(row.getReceiveTime());
            result.add(excel);
        }
        return result;
    }

    private Set<Long> resolveWeighbridgeIds(WeighbridgeRecordPageReqVo reqVo) {
        if (reqVo.getWeighbridgeId() != null) {
            KwsWeighbridge weighbridge = kwsWeighbridgeRepository.findAvailableById(reqVo.getWeighbridgeId());
            if (weighbridge == null || !checkEntPermission(weighbridge.getEntId())) {
                return Collections.emptySet();
            }
            return Collections.singleton(weighbridge.getId());
        }
        Set<Long> entIds = resolveAuthorizedEntIds();
        List<KwsWeighbridge> weighbridges;
        if (LoginUserHolder.isManager()) {
            weighbridges = kwsWeighbridgeRepository.listByNameAndCode(reqVo.getWeighbridgeName(), reqVo.getUniqueCode(), null);
        } else if (entIds.isEmpty()) {
            return Collections.emptySet();
        } else {
            weighbridges = kwsWeighbridgeRepository.listByNameAndCode(reqVo.getWeighbridgeName(), reqVo.getUniqueCode(), entIds);
        }
        return weighbridges.stream().map(KwsWeighbridge::getId).collect(Collectors.toCollection(LinkedHashSet::new));
    }

    private boolean checkEntPermission(Long entId) {
        return LoginUserHolder.isManager() || resolveAuthorizedEntIds().contains(entId);
    }

    private Set<Long> resolveAuthorizedEntIds() {
        if (LoginUserHolder.isManager()) {
            return Collections.emptySet();
        }
        Set<Long> result = new LinkedHashSet<>();
        if (LoginUserHolder.getEntId() != null) {
            result.add(LoginUserHolder.getEntId());
        }
        result.addAll(LoginUserHolder.getAuthEntIdList());
        result.addAll(LoginUserHolder.getChildEntList());
        return result;
    }

    private Map<Long, KwsWeighbridge> weighbridgeMap(Collection<Long> weighbridgeIds) {
        if (weighbridgeIds == null || weighbridgeIds.isEmpty()) {
            return Collections.emptyMap();
        }
        return kwsWeighbridgeRepository.listByIds(weighbridgeIds).stream()
                .filter(item -> Objects.equals(item.getDelFlag(), 0))
                .collect(Collectors.toMap(KwsWeighbridge::getId, item -> item, (a, b) -> a));
    }

    private Map<Long, String> enterpriseNameMap(Collection<Long> entIds) {
        if (entIds == null || entIds.isEmpty()) {
            return Collections.emptyMap();
        }
        return kwsEnterpriseRepository.listByIds(entIds).stream()
                .collect(Collectors.toMap(KwsEnterprise::getId, KwsEnterprise::getFirmName, (a, b) -> a));
    }



    /**
     * 车牌验证
     * @param request 地磅上报请求参数
     * @return 是否保存成功
     */
    public LicensePlateValidateResponse handleValidateLicensePlate(LicensePlateValidateRequest request) {
        log.info("车牌验证, 车牌:{}", request.getLicensePlate());
        LicensePlateValidateResponse response = new LicensePlateValidateResponse();
        ValidateLicensePlate validateLicensePlate;
        //查询车牌是不存在
        try {
            validateLicensePlate = validateLicensePlateService.queryByLicensePlate(request.getLicensePlate(), request.getUuid());
        } catch (Exception e) {
            log.error("车牌验证失败，请重新识别或联系管理员", e);
            return getValidateLicensePlateError(response);
        }

        if (validateLicensePlate != null) {
            log.info("车牌验证成功");
            response.setStatus(Boolean.TRUE);
            response.setCode(200);
            response.setMessage("车牌验证成功");

            response.setData(new LicensePlateValidateResponse.Data());
            response.getData().setTimestamp(System.currentTimeMillis() / 1000);
            response.getData().setScreen_message("车牌验证成功");
            response.getData().setVoice_message("车牌验证成功");
            response.getData().setWarning(null);
            return response;
        } else {
            return getValidateLicensePlateError(response);
        }
    }
    private LicensePlateValidateResponse getValidateLicensePlateError(LicensePlateValidateResponse response) {
        log.info("车牌验证失败");
        response.setStatus(Boolean.FALSE);
        response.setCode(400);
        response.setMessage("车牌验证异常");

        response.setData(new LicensePlateValidateResponse.Data());
        response.getData().setTimestamp(System.currentTimeMillis()/1000);
        response.getData().setScreen_message("车牌验证失败");
        response.getData().setVoice_message("车牌验证失败");
        response.getData().setWarning(null);
        return response;
    }

    /**
     * 处理地磅过磅数据上报
     * @param request 地磅上报请求参数
     * @return 是否保存成功
     */
    public LicensePlateValidateResponse handleWeighbridgePush(WeighbridgePushRequest request) {
        log.info("处理地磅数据上报 - 车牌:{}, 地磅编号:{}, 重量:{}, 时间戳:{}",
                request.getLicensePlate(),
                request.getWeighbridgeCode(),
                request.getGrossWeight(),
                request.getTimestamp());
        LicensePlateValidateResponse licensePlateValidateResponse = new LicensePlateValidateResponse();
        if (StringUtils.isAnyBlank(request.getLicensePlate(), request.getWeighbridgeCode()) || Objects.isNull(request.getGrossWeight()) || Objects.isNull(request.getTimestamp())) {
            return getLicensePlateValidateResponse(request, licensePlateValidateResponse);
        }
        try {
            KwsWeighbridge weighbridge = kwsWeighbridgeRepository.findByUniqueCode(request.getWeighbridgeCode().trim());
            if (weighbridge == null || Objects.equals(weighbridge.getDelFlag(), 1)) {
                log.error("地磅数据保存失败 - 地磅不存在, 地磅编号: {}", request.getWeighbridgeCode());
                return getLicensePlateValidateResponse(request, licensePlateValidateResponse);
            }

            KwsWeighbridgeRecord record = buildWeighbridgeRecord(request, weighbridge.getId());
            boolean saved = kwsWeighbridgeRecordRepository.save(record);
            if (saved) {
                // 异步处理图片上传
                updateImageUrls(request, record);
                licensePlateValidateResponse.setStatus(true);
                licensePlateValidateResponse.setCode(200);
                licensePlateValidateResponse.setMessage("数据上报成功");
                LicensePlateValidateResponse.Data data = new LicensePlateValidateResponse.Data();
                data.setTimestamp(resolveSecondTimestamp(request.getTimestamp()));
                data.setScreen_message("数据上报成功");
                data.setVoice_message("数据上报成功");
                licensePlateValidateResponse.setData(data);
                log.info("地磅数据保存成功 - ID: {}, 车牌: {}", record.getId(), record.getTruckNo());
                return licensePlateValidateResponse;
            } else {
                log.error("地磅数据保存失败 - 车牌: {}", request.getLicensePlate());
                return getLicensePlateValidateResponse(request, licensePlateValidateResponse);
            }

        } catch (Exception e) {
            log.error("地磅数据上报处理异常", e);
            return getLicensePlateValidateResponse(request, licensePlateValidateResponse);
        }
    }
    private void updateImageUrls(WeighbridgePushRequest request, KwsWeighbridgeRecord record) {
        MultipartFile[] images = request.getImages();
        if (images == null || images.length == 0) {
            return;
        }

        int validImageCount = (int) java.util.Arrays.stream(images)
                .filter(Objects::nonNull)
                .count();
        if (validImageCount == 0) {
            return;
        }

        // kws_weighbridge_record 当前没有图片URL字段，先只记录上传事实，避免保留无效的旧依赖代码。
        log.info("地磅记录收到图片但当前未落库, recordId: {}, truckNo: {}, imageCount: {}",
                record.getId(), request.getLicensePlate(), validImageCount);
    }
    private static LicensePlateValidateResponse getLicensePlateValidateResponse(WeighbridgePushRequest request, LicensePlateValidateResponse licensePlateValidateResponse) {

        licensePlateValidateResponse.setStatus(false);
        licensePlateValidateResponse.setCode(400);
        licensePlateValidateResponse.setMessage("数据上报失败");
        LicensePlateValidateResponse.Data data = new LicensePlateValidateResponse.Data();
        String timestampStr = request.getTimestamp().toString();
        if (timestampStr.length() == 10) {
            // 秒级时间戳
            data.setTimestamp(request.getTimestamp());
        } else if (timestampStr.length() == 13) {
            // 毫秒级时间戳
            long l = request.getTimestamp() / 1000;
            data.setTimestamp(l);
        }

        data.setVoice_message("数据上报失败");
        licensePlateValidateResponse.setData(data);
        return licensePlateValidateResponse;
    }

    private KwsWeighbridgeRecord buildWeighbridgeRecord(WeighbridgePushRequest request, Long weighbridgeId) {
        Date now = new Date();
        return new KwsWeighbridgeRecord()
                .setWeighbridgeId(weighbridgeId)
                .setTruckNo(request.getLicensePlate().trim())
                .setWeight(request.getGrossWeight())
                .setReceiveTime(resolveReceiveTime(request.getTimestamp()))
                .setCreateBy(0L)
                .setCreateTime(now)
                .setUpdateBy(0L)
                .setUpdateTime(now)
                .setDelFlag(0);
    }

    private Date resolveReceiveTime(Long timestamp) {
        long secondTimestamp = resolveSecondTimestamp(timestamp);
        return new Date(secondTimestamp * 1000);
    }

    private long resolveSecondTimestamp(Long timestamp) {
        if (timestamp == null) {
            return System.currentTimeMillis() / 1000;
        }
        String timestampStr = timestamp.toString();
        if (timestampStr.length() == 13) {
            return timestamp / 1000;
        }
        return timestamp;
    }

}
