package com.kym.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.github.pagehelper.PageHelper;
import com.kym.common.exception.BusinessException;
import com.kym.common.utils.CommUtil;
import com.kym.entity.DeviceConfig;
import com.kym.entity.WashDevice;
import com.kym.entity.WashOrder;
import com.kym.entity.common.PageBean;
import com.kym.entity.queryParams.DeviceQueryParams;
import com.kym.entity.vo.DevicePriceVo;
import com.kym.entity.vo.WashDeviceVo;
import com.kym.mapper.WashDeviceMapper;
import com.kym.service.DeviceConfigService;
import com.kym.service.DeviceRelationService;
import com.kym.service.WashDeviceService;
import com.kym.service.WashOrderService;
import com.kym.service.aliyun.lot.AliyunLotClient;
import com.kym.service.cache.KymCache;
import com.kym.service.mybatisplus.MyBaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 洗车设备表 服务实现类
 * </p>
 *
 * @author skyline
 * @since 2024-10-09
 */
@Slf4j
@Service
public class WashDeviceServiceImpl extends MyBaseServiceImpl<WashDeviceMapper, WashDevice> implements WashDeviceService {

    private WashOrderService washOrderService;

    private DeviceConfigService deviceConfigService;

    private DeviceRelationService deviceRelationService;

    public WashDeviceServiceImpl(WashOrderService washOrderService, DeviceConfigService deviceConfigService, DeviceRelationService deviceRelationService) {
        this.washOrderService = washOrderService;
        this.deviceConfigService = deviceConfigService;
        this.deviceRelationService = deviceRelationService;
    }


    //region 小程序

    /**
     * 获取设备列表
     *
     * @param params
     * @return
     */
    @Override
    public List<WashDeviceVo> listWashDevice(DeviceQueryParams params) {
        var list = lambdaQuery()
                .eq(CommUtil.isNotEmptyAndNull(params.getId()), WashDevice::getId, params.getId())
                .eq(CommUtil.isNotEmptyAndNull(params.getStationId()), WashDevice::getStationId, params.getStationId())
                .orderByAsc(WashDevice::getSequence)
                .orderByAsc(WashDevice::getState)
                .orderByAsc(WashDevice::getDeviceName)
                .list();

        if (list.isEmpty()) {
            return Collections.emptyList();
        }

        var configMap = loadDeviceConfigMap(list);

        var voList = new ArrayList<WashDeviceVo>();
        //TODO 根据订单查询占用中的设备
//        var currentUserId = StpUtil.getLoginIdAsLong();
        for (WashDevice washDevice : list) {
            var vo = new WashDeviceVo();
//            .setCurrentUserId(currentUserId);
            BeanUtils.copyProperties(washDevice, vo);
            vo.setShortId(KymCache.INSTANCE.getShortIdByProductKeyAndDeviceName(washDevice.getProductKey(), washDevice.getDeviceName()));
            vo.setPrice(toDevicePriceVo(configMap.get(washDevice.getDeviceConfigId())));
            voList.add(vo);
        }
        return voList;
    }


    /**
     * 根据设备短id获取设备信息
     *
     * @param shortId
     * @return
     */
    @Override
    public WashDeviceVo getDevice(String shortId) {
        var productKeyAndDeviceName = KymCache.INSTANCE.getProductKeyAndDeviceNameByWashShortId(shortId);
        // 校验操作人权限
        var order = washOrderService.lambdaQuery()
                .eq(WashOrder::getProductKey, productKeyAndDeviceName[0])
                .eq(WashOrder::getDeviceName, productKeyAndDeviceName[1])
                .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
                .one();

        if (order == null || order.getUserId() == StpUtil.getLoginIdAsLong()) {
            var washDevice = lambdaQuery()
                    .eq(WashDevice::getProductKey, productKeyAndDeviceName[0])
                    .eq(WashDevice::getDeviceName, productKeyAndDeviceName[1])
                    .one();

            var vo = new WashDeviceVo().setCurrentUserId(StpUtil.getLoginIdAsLong());
            BeanUtils.copyProperties(washDevice, vo.setShortId(shortId));

            if (washDevice != null && washDevice.getDeviceConfigId() != null) {
                var config = deviceConfigService.getById(washDevice.getDeviceConfigId());
                vo.setPrice(toDevicePriceVo(config));
            }
            return vo;
        } else {
            throw new BusinessException("设备他人使用中!");
        }

    }


    @Override
    public String startDevice(String shortId) {
        var productKeyAndDeviceName = KymCache.INSTANCE.getProductKeyAndDeviceNameByWashShortId(shortId);
        return washOrderService.createOrder(new DeviceQueryParams(shortId, productKeyAndDeviceName[0], productKeyAndDeviceName[1]));
    }

    @Override
    public void stopDevice(String shortId) {
        var productKeyAndDeviceName = KymCache.INSTANCE.getProductKeyAndDeviceNameByWashShortId(shortId);
        washOrderService.closeOrder(new DeviceQueryParams(shortId, productKeyAndDeviceName[0], productKeyAndDeviceName[1]));
    }

    //endregion

    //region 管理后台
    @Override
    public Object detail(long id) {
        return getById(id);
    }

    @Override
    public void remove(long id) {
        var device = getById(id);
        CommUtil.asserts(device != null, "设备不存在");

        try {
            AliyunLotClient.deleteDevice(device.getProductKey(), device.getDeviceName());
        } catch (Exception e) {
            log.warn("阿里云IoT删除设备失败(已忽略，继续清理本地数据): productKey={}, deviceName={}", device.getProductKey(), device.getDeviceName(), e);
        }

        deviceRelationService.removeByDevice(device.getProductKey(), device.getDeviceName());
        super.removeById(id);
    }

    @Override
    public void modify(WashDevice device) {
        CommUtil.assertsNonNulls(List.of(device.getDeviceName(), device.getStationId(), device.getProductKey(), device.getId()), "参数异常");
        List<WashDevice> list = lambdaQuery()
                .eq(WashDevice::getStationId, device.getStationId())
                .eq(WashDevice::getDeviceName, device.getDeviceName())
                .eq(WashDevice::getProductKey, device.getProductKey())
                .list();
        CommUtil.asserts(list.size() <= 1, "设备信息异常");
        if (list.size() == 1) {
            CommUtil.asserts(list.get(0).getDeviceName().equalsIgnoreCase(device.getDeviceName()), "站点已存在");
        }
        if (device.getSequence() != null) {
            Long seqCount = lambdaQuery()
                    .eq(WashDevice::getStationId, device.getStationId())
                    .eq(WashDevice::getSequence, device.getSequence())
                    .ne(WashDevice::getId, device.getId())
                    .count();
            CommUtil.asserts(seqCount == 0, "该站点下工位序号已存在");
        }
        updateById(device);
    }

    @Override
    public void add(WashDevice device) {
        // productKey 统一使用配置文件中的值，不接受前端传入
        device.setProductKey(AliyunLotClient.getProductKey());
        CommUtil.asserts(CommUtil.isNotEmptyAndNull(device.getDeviceName()), "设备名称不能为空");

        Long count = lambdaQuery()
                .eq(WashDevice::getStationId, device.getStationId())
                .eq(WashDevice::getDeviceName, device.getDeviceName())
                .eq(WashDevice::getProductKey, device.getProductKey()).count();
        CommUtil.asserts(count == 0, "设备已存在");
        if (device.getSequence() != null) {
            Long seqCount = lambdaQuery()
                    .eq(WashDevice::getStationId, device.getStationId())
                    .eq(WashDevice::getSequence, device.getSequence())
                    .count();
            CommUtil.asserts(seqCount == 0, "该站点下工位序号已存在");
        }

        try {
            AliyunLotClient.registerDevice(device.getProductKey(), device.getDeviceName());
        } catch (Exception e) {
            log.error("阿里云IoT注册设备失败: productKey={}, deviceName={}", device.getProductKey(), device.getDeviceName(), e);
            throw new BusinessException("阿里云物联网平台注册设备失败: " + e.getMessage());
        }

        save(device);
    }

    @Override
    public PageBean<WashDeviceVo> list(DeviceQueryParams query) {
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        List<WashDevice> list = lambdaQuery()
                .eq(CommUtil.isNotEmptyAndNull(query.getStationId()), WashDevice::getStationId, query.getStationId())
                .eq(query.getHasFoam() != null, WashDevice::getHasFoam, query.getHasFoam())
                .eq(query.getHasWater() != null, WashDevice::getHasWater, query.getHasWater())
                .eq(query.getHasPa() != null, WashDevice::getHasPa, query.getHasPa())
                .orderByAsc(WashDevice::getSequence)
                .list();

        if (list.isEmpty()) {
            return new PageBean<>(Collections.emptyList());
        }

        // 设备配置ID-设备配置Map
        var deviceConfigMap = deviceConfigService.lambdaQuery()
                .in(DeviceConfig::getId, list.stream().map(WashDevice::getDeviceConfigId).toList())
                .list().stream().collect(Collectors.toMap(DeviceConfig::getId, Function.identity()));

        var voList = new ArrayList<WashDeviceVo>();
        list.forEach(item -> {
            var vo = new WashDeviceVo();
            BeanUtils.copyProperties(item, vo);
            vo.setShortId(KymCache.INSTANCE.getShortIdByProductKeyAndDeviceName(item.getProductKey(), item.getDeviceName()));
            vo.setStationName(KymCache.INSTANCE.getStationNameById(item.getStationId()));
            vo.setDeviceConfigName(deviceConfigMap.get(item.getDeviceConfigId()).getName());
            voList.add(vo);
        });
        return new PageBean<>(voList);
    }

    @Override
    public void batchUpdateSequence(List<WashDevice> devices) {
        devices.forEach(device -> {
            lambdaUpdate()
                    .eq(WashDevice::getId, device.getId())
                    .set(WashDevice::getSequence, device.getSequence())
                    .update();
        });
    }

    //endregion

    //region 价格公示

    private java.util.Map<Long, DeviceConfig> loadDeviceConfigMap(List<WashDevice> devices) {
        var configIds = devices.stream().map(WashDevice::getDeviceConfigId).filter(id -> id != null).toList();
        if (configIds.isEmpty()) {
            return Collections.emptyMap();
        }
        return deviceConfigService.lambdaQuery()
                .in(DeviceConfig::getId, configIds)
                .list().stream().collect(Collectors.toMap(DeviceConfig::getId, Function.identity()));
    }

    private DevicePriceVo toDevicePriceVo(DeviceConfig config) {
        if (config == null) {
            return null;
        }
        return new DevicePriceVo()
                .setPriceSpace(config.getPriceSpace())
                .setPriceWater(config.getPriceWater())
                .setPriceFoam(config.getPriceFoam())
                .setPriceCleaner(config.getPriceCleaner())
                .setPriceTap(config.getPriceTap())
                .setPriceUserExt(config.getPriceUserExt())
                .setPriceCoat(config.getPriceCoat())
                .setPriceBlow(config.getPriceBlow())
                .setAmountMinLimit(config.getAmountMinLimit())
                .setPrepayMoney(config.getPrepayMoney());
    }

    //endregion

}
