package com.erp.logistics.service;

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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.erp.logistics.dto.request.TraceSyncRequest;
import com.erp.logistics.dto.request.WaybillStatusQueryRequest;
import com.erp.common.core.model.PageResponse;
import com.erp.logistics.dto.response.TraceResponse;
import com.erp.logistics.dto.response.WaybillStatusResponse;
import com.erp.logistics.entity.LogisticsTrace;
import com.erp.logistics.entity.WaybillStatus;
import com.erp.logistics.mapper.LogisticsTraceMapper;
import com.erp.logistics.mapper.WaybillStatusMapper;
import com.erp.logistics.service.adapter.CarrierAdapter;
import com.erp.logistics.service.adapter.CarrierAdapterFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 物流服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LogisticsService extends ServiceImpl<WaybillStatusMapper, WaybillStatus> {

    private final WaybillStatusMapper waybillStatusMapper;
    private final LogisticsTraceMapper logisticsTraceMapper;
    private final CarrierAdapterFactory carrierAdapterFactory;
    private final TraceSyncService traceSyncService;
    private final RedisTemplate<String, Object> redisTemplate;

    private static final String CACHE_KEY_PREFIX = "logistics:waybill:";
    private static final Duration CACHE_TTL = Duration.ofMinutes(10);

    // ==================== 轨迹查询 ====================

    /**
     * 查询物流轨迹
     */
    public TraceResponse getTraces(String waybillNo) {
        // 先查数据库
        List<LogisticsTrace> traces = logisticsTraceMapper.selectByWaybillNoOrderByTime(waybillNo);

        if (traces.isEmpty()) {
            // 尝试同步
            traceSyncService.syncSingle(waybillNo, null, false);
            traces = logisticsTraceMapper.selectByWaybillNoOrderByTime(waybillNo);
        }

        if (traces.isEmpty()) {
            return null;
        }

        LogisticsTrace first = traces.get(0);
        LogisticsTrace last = traces.get(traces.size() - 1);

        return TraceResponse.builder()
                .waybillNo(waybillNo)
                .carrier(first.getCarrier())
                .carrierName(getCarrierName(first.getCarrier()))
                .status(last.getStatus())
                .statusLabel(last.getStatusLabel())
                .lastTraceTime(last.getTraceTime())
                .totalTraces(traces.size())
                .traces(traces.stream().map(t -> TraceResponse.TraceNode.builder()
                        .status(t.getStatus())
                        .statusLabel(t.getStatusLabel())
                        .location(t.getLocation())
                        .description(t.getDescription())
                        .traceTime(t.getTraceTime())
                        .build())
                        .collect(Collectors.toList()))
                .build();
    }

    /**
     * 查询物流轨迹（增强版：含统计、时间轴分段、预计送达）
     */
    public TraceResponse getTracesEnhanced(String waybillNo) {
        // 先查数据库
        List<LogisticsTrace> traces = logisticsTraceMapper.selectByWaybillNoOrderByTime(waybillNo);

        if (traces.isEmpty()) {
            traceSyncService.syncSingle(waybillNo, null, false);
            traces = logisticsTraceMapper.selectByWaybillNoOrderByTime(waybillNo);
        }

        if (traces.isEmpty()) {
            return null;
        }

        LogisticsTrace first = traces.get(0);
        LogisticsTrace last = traces.get(traces.size() - 1);

        // 途经城市去重
        long transitCityCount = traces.stream()
                .map(LogisticsTrace::getLocation)
                .filter(l -> l != null && !l.isEmpty())
                .distinct()
                .count();

        // 在途天数
        int transitDays = 0;
        if (first.getTraceTime() != null) {
            transitDays = (int) java.time.Duration
                    .between(first.getTraceTime(), last.getTraceTime() != null ? last.getTraceTime() : LocalDateTime.now())
                    .toDays();
        }

        // 异常判断
        String exceptionType = null;
        WaybillStatus status = waybillStatusMapper.selectByWaybillNo(waybillNo);
        if (status != null) {
            if ("EXCEPTION".equals(status.getStatus())) {
                exceptionType = "运单异常";
            } else if (status.getSyncStatus() != null && status.getSyncStatus() == 3) {
                exceptionType = "同步失败";
            } else if (status.getLastTraceTime() != null
                    && !"SIGNED".equals(status.getStatus())
                    && !"RETURNED".equals(status.getStatus())
                    && java.time.Duration.between(status.getLastTraceTime(), LocalDateTime.now()).toHours() > 48) {
                exceptionType = "停滞预警";
            }
        }

        // 预计送达时间（仅派送中有意义）
        LocalDateTime estimatedDelivery = null;
        Boolean isOnTime = null;
        if ("DELIVERING".equals(last.getStatus()) && first.getTraceTime() != null) {
            // 简单估算：取同物流商历史平均时效，这里用创建到当前的时间 + 2小时
            estimatedDelivery = last.getTraceTime().plusHours(2);
        }

        return TraceResponse.builder()
                .waybillNo(waybillNo)
                .carrier(first.getCarrier())
                .carrierName(getCarrierName(first.getCarrier()))
                .status(last.getStatus())
                .statusLabel(last.getStatusLabel())
                .lastTraceTime(last.getTraceTime())
                .totalTraces(traces.size())
                .transitDays(transitDays)
                .transitCityCount((int) transitCityCount)
                .estimatedDelivery(estimatedDelivery)
                .isOnTime(isOnTime)
                .exceptionType(exceptionType)
                .traces(traces.stream().map(t -> TraceResponse.TraceNode.builder()
                        .status(t.getStatus())
                        .statusLabel(t.getStatusLabel())
                        .location(t.getLocation())
                        .description(t.getDescription())
                        .traceTime(t.getTraceTime())
                        .build())
                        .collect(Collectors.toList()))
                .build();
    }

    // ==================== 运单状态查询 ====================

    /**
     * 查询运单状态
     */
    public WaybillStatusResponse getWaybillStatus(String waybillNo) {
        WaybillStatus status = waybillStatusMapper.selectByWaybillNo(waybillNo);
        if (status == null) {
            return null;
        }
        return toResponse(status);
    }

    /**
     * 分页查询运单列表
     */
    public PageResponse<WaybillStatusResponse> queryWaybills(WaybillStatusQueryRequest request) {
        LambdaQueryWrapper<WaybillStatus> wrapper = new LambdaQueryWrapper<>();

        if (request.getWaybillNo() != null && !request.getWaybillNo().isEmpty()) {
            wrapper.eq(WaybillStatus::getWaybillNo, request.getWaybillNo());
        }
        if (request.getCarrier() != null && !request.getCarrier().isEmpty()) {
            wrapper.eq(WaybillStatus::getCarrier, request.getCarrier().toUpperCase());
        }
        if (request.getStatus() != null && !request.getStatus().isEmpty()) {
            wrapper.eq(WaybillStatus::getStatus, request.getStatus());
        }
        if (request.getOrderId() != null) {
            wrapper.eq(WaybillStatus::getOrderId, request.getOrderId());
        }

        wrapper.orderByDesc(WaybillStatus::getUpdatedAt);

        Page<WaybillStatus> page = new Page<>(request.getPageNum(), request.getPageSize());
        IPage<WaybillStatus> result = waybillStatusMapper.selectPage(page, wrapper);

        List<WaybillStatusResponse> records = result.getRecords().stream()
                .map(this::toResponse)
                .collect(Collectors.toList());

        return PageResponse.of(
                records,
                result.getTotal(),
                (int) result.getCurrent(),
                (int) result.getSize()
        );
    }

    // ==================== 轨迹同步 ====================

    /**
     * 同步单条运单轨迹
     */
    @Transactional
    public void syncTraces(TraceSyncRequest request) {
        traceSyncService.syncSingle(request.getWaybillNo(), request.getCarrier(), request.getForceSync());
    }

    // ==================== 运单创建/更新 ====================

    /**
     * 创建或更新运单
     */
    @Transactional
    public WaybillStatusResponse saveOrUpdateWaybill(WaybillStatus waybill) {
        LambdaQueryWrapper<WaybillStatus> wrapper = new LambdaQueryWrapper<WaybillStatus>()
                .eq(WaybillStatus::getWaybillNo, waybill.getWaybillNo());

        WaybillStatus exist = waybillStatusMapper.selectOne(wrapper);
        if (exist != null) {
            waybill.setId(exist.getId());
            waybill.setCreatedAt(exist.getCreatedAt());
            waybillStatusMapper.updateById(waybill);
        } else {
            waybillStatusMapper.insert(waybill);
        }

        // 清除缓存
        clearCache(waybill.getWaybillNo());

        return toResponse(waybill);
    }

    // ==================== 工具方法 ====================

    private WaybillStatusResponse toResponse(WaybillStatus status) {
        return WaybillStatusResponse.builder()
                .id(status.getId())
                .waybillNo(status.getWaybillNo())
                .carrier(status.getCarrier())
                .carrierName(getCarrierName(status.getCarrier()))
                .status(status.getStatus())
                .statusLabel(status.getStatusLabel())
                .location(status.getLocation())
                .description(status.getDescription())
                .lastTraceTime(status.getLastTraceTime())
                .signedTime(status.getSignedTime())
                .syncStatus(status.getSyncStatus())
                .syncFailReason(status.getSyncFailReason())
                .orderId(status.getOrderId())
                .orderNo(status.getOrderNo())
                .receiverName(status.getReceiverName())
                .updatedAt(status.getUpdatedAt())
                .build();
    }

    private String getCarrierName(String carrierCode) {
        if (carrierCode == null) {
            return "未知";
        }
        try {
            CarrierAdapter adapter = carrierAdapterFactory.getAdapter(carrierCode);
            return adapter.getCarrierName();
        } catch (Exception e) {
            Map<String, String> carrierNames = Map.of(
                    "SF", "顺丰速运",
                    "YTO", "圆通速递",
                    "ZTO", "中通快递",
                    "YUNDA", "韵达快递"
            );
            return carrierNames.getOrDefault(carrierCode.toUpperCase(), carrierCode);
        }
    }

    private void clearCache(String waybillNo) {
        try {
            redisTemplate.delete(CACHE_KEY_PREFIX + waybillNo);
        } catch (Exception e) {
            log.warn("清除缓存失败: {}", waybillNo, e);
        }
    }
}
