package com.haha.service.impl;

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.haha.common.constant.DeviceConstants;
import com.haha.common.constant.OrderConstants;
import com.haha.common.exception.BusinessException;
import com.haha.common.utils.EntityLabelUtils;
import com.haha.entity.Device;
import com.haha.entity.Order;
import com.haha.entity.Shop;
import com.haha.mapper.DeviceMapper;
import com.haha.mapper.ShopMapper;
import com.haha.service.DeviceService;
import com.haha.service.OrderService;
import com.haha.common.utils.OrderUtils;
import com.haha.common.vo.OpenDoorVO;
import com.haha.sdk.HahaClient;
import com.haha.sdk.exception.HahaException;
import com.haha.sdk.model.DeviceOnlineStatus;
import com.haha.sdk.model.OpenDoorResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {

    private final HahaClient hahaClient;
    private final OrderService orderService;
    private final ShopMapper shopMapper;

    @Override
    public IPage<Device> getPage(int page, int pageSize, String deviceId, Long shopId, Integer status) {
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        
        wrapper.like(deviceId != null && !deviceId.isEmpty(), Device::getDeviceId, deviceId)
               .eq(shopId != null, Device::getShopId, shopId)
               .eq(status != null, Device::getStatus, status)
               .orderByDesc(Device::getCreateTime);

        IPage<Device> devicePage = this.page(new Page<>(page, pageSize), wrapper);
        
        // 填充额外字段
        devicePage.getRecords().forEach(this::fillDeviceLabels);
        
        return devicePage;
    }

    @Override
    public Device getDetailById(Long id) {
        Device device = this.getById(id);
        if (device == null) {
            return null;
        }
        fillDeviceLabels(device);
        return device;
    }

    @Override
    public Map<String, Object> getStatistics() {
        Map<String, Object> statistics = new HashMap<>();

        // 总设备数
        long total = this.count();
        statistics.put("total", total);

        // 在线设备数
        long online = this.lambdaQuery()
                .eq(Device::getStatus, DeviceConstants.STATUS_ONLINE)
                .count();
        statistics.put("online", online);

        // 离线设备数
        statistics.put("offline", total - online);

        // TODO: 后续从订单服务获取销售额数据
        statistics.put("totalSales", "0.00");
        statistics.put("todaySales", "0.00");
        statistics.put("avgTemperature", "0.0");

        return statistics;
    }

    @Override
    public boolean openDoor(Long id, String doorIndex) {
        Device device = this.getById(id);
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }
        
        log.info("远程开门: deviceId={}, doorIndex={}", device.getDeviceId(), doorIndex);
        
        // TODO: 调用SDK发送开门指令
        
        return true;
    }

    @Override
    public boolean setTemperature(Long id, Double temperature) {
        Device device = this.getById(id);
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }
        
        log.info("设置温度: deviceId={}, temperature={}", device.getDeviceId(), temperature);
        
        // TODO: 调用SDK设置温度
        
        return true;
    }

    @Override
    public boolean setVolume(Long id, Integer volume) {
        Device device = this.getById(id);
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }
        
        log.info("设置音量: deviceId={}, volume={}", device.getDeviceId(), volume);
        
        // TODO: 调用SDK设置音量
        
        return true;
    }

    @Override
    public List<Device> getNearbyDevices(Double longitude, Double latitude, Double distance) {
        // 这里需要实现获取附近设备的逻辑，暂时返回所有设备
        return list();
    }

    @Override
    public Device getDeviceBySn(String deviceId) {
        return lambdaQuery().eq(Device::getDeviceId, deviceId).one();
    }

    @Override
    public boolean updateDeviceStatus(String deviceId, Integer status) {
        return lambdaUpdate().eq(Device::getDeviceId, deviceId).set(Device::getStatus, status).update();
    }

    @Override
    public List<Device> getDeviceListByArea(String province, String city, String district) {
        // 这里需要实现根据区域获取设备列表的逻辑，暂时返回所有设备
        return list();
    }

    @Override
    public boolean updateInventoryHash(String deviceId, String inventoryHash) {
        return lambdaUpdate().eq(Device::getDeviceId, deviceId).set(Device::getCurrentInventoryHash, inventoryHash).update();
    }

    @Override
    public OpenDoorVO scanOpenDoor(String deviceId, Long userId) throws HahaException {
        log.info("用户 {} 请求打开设备 {}", userId, deviceId);

        // 1. 检查设备在线状态
        DeviceOnlineStatus onlineStatus = hahaClient.getDeviceApi().getOnlineStatus(deviceId);
        if (onlineStatus.getIsOnline() != 1) {
            log.warn("设备 {} 当前离线", deviceId);
            throw new BusinessException("设备当前离线，请稍后再试");
        }

        // 2. 检查是否多门单开
        Integer multiDoorType = hahaClient.getDeviceApi().isMultiDoorUnique(deviceId);
        String doorIndex = null;

        // 如果是多门单开设备，默认打开A门
        if (multiDoorType != null && multiDoorType > 0) {
            doorIndex = DeviceConstants.DOOR_A;
            log.info("设备 {} 是多门单开设备，类型: {}，将打开A门", deviceId, multiDoorType);
        }

        // 3. 生成商户用户编号并开门
        String openType = "OUT"; // OUT表示消费，IN表示上货
        String source = "MINIAPP"; // 请求来源

        OpenDoorResult openResult = hahaClient.getDeviceApi().openDoor(deviceId, String.valueOf(userId), openType, doorIndex, source);

        // 4. 创建本地订单记录
        Order order = new Order();
        order.setOrderNo(OrderUtils.getOrderNo());
        order.setActivityId(openResult.getActivityId());
//         order.setOutTradeNo(""); todo 收到支付完成的通知时更新为支付订单号
        order.setUserId(userId);
        order.setDeviceId(deviceId);
        order.setStatus(OrderConstants.STATUS_PENDING_PAYMENT);
        order.setPayStatus(OrderConstants.PAY_STATUS_UNPAID);
        order.setCreateTime(LocalDateTime.now());

        boolean saved = orderService.save(order);
        if (!saved) {
            log.warn("订单 {} 保存失败，但开门已成功", order.getOrderNo());
        }

        // 5. 返回成功结果
        log.info("开门成功 - 设备: {}, 活动ID: {}, 用户ID: {}", deviceId, openResult.getActivityId(), openResult.getUserId());

        return OpenDoorVO.builder()
            .doorOpened(true)
            .activityId(openResult.getActivityId())
            .userId(openResult.getUserId())
            .deviceId(deviceId)
            .doorIndex(doorIndex != null ? doorIndex : DeviceConstants.DEFAULT_DOOR_INDEX)
            .build();
    }

    @Override
    public boolean linkToShop(Long deviceId, Long shopId) {
        Device device = this.getById(deviceId);
        if (device == null) {
            throw new BusinessException("设备不存在");
        }
        
        device.setShopId(shopId);
        device.setUpdateTime(LocalDateTime.now());
        
        boolean result = this.updateById(device);
        if (result) {
            log.info("设备关联门店成功: deviceId={}, shopId={}", deviceId, shopId);
        }
        return result;
    }

    @Override
    public int batchLinkToShop(List<Long> deviceIds, Long shopId) {
        int count = 0;
        for (Long deviceId : deviceIds) {
            try {
                if (linkToShop(deviceId, shopId)) {
                    count++;
                }
            } catch (Exception e) {
                log.error("设备关联门店失败: deviceId={}, error={}", deviceId, e.getMessage());
            }
        }
        log.info("批量关联门店完成: 总数={}, 成功={}", deviceIds.size(), count);
        return count;
    }

    @Override
    public List<Device> getUnlinkedDevices() {
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        wrapper.isNull(Device::getShopId)
               .or()
               .eq(Device::getShopId, 0);
        wrapper.orderByDesc(Device::getCreateTime);
        return this.list(wrapper);
    }

    /**
     * 填充设备标签字段
     */
    private void fillDeviceLabels(Device device) {
        // 设备状态标签
        if (device.getStatus() != null) {
            var statusLabel = EntityLabelUtils.getStatusLabel("device", device.getStatus());
            device.setStatusLabel(statusLabel.getLabel());
            device.setStatusColor(statusLabel.getColor());
            device.setIsOnline(DeviceConstants.isOnline(device.getStatus()));
        }
        
        // 填充门店信息
        if (device.getShopId() != null && device.getShopName() == null) {
            Shop shop = shopMapper.selectById(device.getShopId());
            if (shop != null) {
                device.setShopName(shop.getName());
                if (device.getAddress() == null) {
                    device.setAddress(shop.getAddress());
                }
            }
        }
        
        // 设置默认值
        setDefaultValues(device);
    }
    
    /**
     * 设置设备默认值
     */
    private void setDefaultValues(Device device) {
        if (device.getShopName() == null) {
            device.setShopName("默认门店");
        }
        if (device.getAddress() == null) {
            device.setAddress("-");
        }
        if (device.getDeviceTypeLabel() == null) {
            device.setDeviceTypeLabel(DeviceConstants.TYPE_SMART_CABINET);
        }
        if (device.getTemperature() == null) {
            device.setTemperature("0.0");
        }
        if (device.getVolume() == null) {
            device.setVolume(8);
        }
        if (device.getDoorCount() == null) {
            device.setDoorCount(1);
        }
        if (device.getLayerCount() == null) {
            device.setLayerCount(5);
        }
        if (device.getTotalSales() == null) {
            device.setTotalSales("0.00");
        }
        if (device.getTodaySales() == null) {
            device.setTodaySales("0.00");
        }
        if (device.getOrderCount() == null) {
            device.setOrderCount(0);
        }
    }
}
