package com.haha.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.enums.CommonStatus;
import com.haha.common.exception.BusinessException;
import com.haha.common.vo.ShopDeviceVO;
import com.haha.common.vo.ShopSelectVO;
import com.haha.common.vo.ShopStatisticsVO;
import com.haha.entity.Device;
import com.haha.entity.Shop;
import com.haha.mapper.ShopMapper;
import com.haha.service.DeviceService;
import com.haha.service.ShopService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

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

/**
 * 门店服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements ShopService {

    private final ShopMapper shopMapper;
    private final DeviceService deviceService;

    @Override
    public IPage<Shop> getPage(int page, int pageSize, Map<String, Object> params) {
        Page<Shop> pageParam = new Page<>(page, pageSize);
        
        LambdaQueryWrapper<Shop> wrapper = new LambdaQueryWrapper<>();
        
        // 门店名称模糊查询
        String name = (String) params.get("name");
        wrapper.like(StringUtils.hasText(name), Shop::getName, name);
        
        // 城市查询
        String city = (String) params.get("city");
        wrapper.eq(StringUtils.hasText(city), Shop::getCity, city);
        
        // 状态查询
        Object statusObj = params.get("status");
        if (statusObj != null && !statusObj.toString().isEmpty()) {
            Integer status = Integer.valueOf(statusObj.toString());
            wrapper.eq(Shop::getStatus, status);
        }
        
        // 按创建时间倒序
        wrapper.orderByDesc(Shop::getCreateTime);
        
        IPage<Shop> shopPage = this.page(pageParam, wrapper);

        // 批量填充设备统计信息（1 次查询替代 2N 次 COUNT）
        List<Shop> records = shopPage.getRecords();
        if (!records.isEmpty()) {
            List<Long> shopIds = records.stream().map(Shop::getId).toList();
            // 一次查所有关联设备，在内存中按 shopId 分组统计
            List<Device> allDevices = deviceService.lambdaQuery()
                    .in(Device::getShopId, shopIds)
                    .select(Device::getShopId, Device::getStatus)
                    .list();
            Map<Long, Integer> deviceCountMap = new HashMap<>();
            Map<Long, Integer> onlineCountMap = new HashMap<>();
            for (Device d : allDevices) {
                deviceCountMap.merge(d.getShopId(), 1, Integer::sum);
                if (d.getStatus() != null && d.getStatus() == DeviceConstants.STATUS_ONLINE) {
                    onlineCountMap.merge(d.getShopId(), 1, Integer::sum);
                }
            }
            for (Shop shop : records) {
                shop.setDeviceCount(deviceCountMap.getOrDefault(shop.getId(), 0));
                shop.setOnlineCount(onlineCountMap.getOrDefault(shop.getId(), 0));
                fillShopLabels(shop);
            }
        }

        return shopPage;
    }

    @Override
    public List<Shop> queryByName(String name) {
        return this.lambdaQuery()
                .like(StringUtils.hasText(name), Shop::getName, name)
                .orderByDesc(Shop::getCreateTime)
                .list();
    }

    @Override
    public List<Shop> queryByCity(String city) {
        return this.lambdaQuery()
                .eq(StringUtils.hasText(city), Shop::getCity, city)
                .orderByDesc(Shop::getCreateTime)
                .list();
    }

    @Override
    public List<Shop> queryByStatus(Integer status) {
        return this.lambdaQuery()
                .eq(status != null, Shop::getStatus, status)
                .orderByDesc(Shop::getCreateTime)
                .list();
    }

    @Override
    public Shop getShopWithStats(Long id) {
        Map<String, Object> map = shopMapper.selectShopWithStats(id);
        if (map == null || map.isEmpty()) {
            return null;
        }
        
        Shop shop = new Shop();
        shop.setId(((Number) map.get("id")).longValue());
        shop.setShopCode((String) map.get("shop_code"));
        shop.setName((String) map.get("name"));
        shop.setAddress((String) map.get("address"));
        shop.setProvince((String) map.get("province"));
        shop.setCity((String) map.get("city"));
        shop.setDistrict((String) map.get("district"));
        
        Object longitude = map.get("longitude");
        if (longitude != null) {
            shop.setLongitude(((Number) longitude).doubleValue());
        }
        Object latitude = map.get("latitude");
        if (latitude != null) {
            shop.setLatitude(((Number) latitude).doubleValue());
        }
        
        shop.setContactName((String) map.get("contact_name"));
        shop.setContactPhone((String) map.get("contact_phone"));
        shop.setBusinessHours((String) map.get("business_hours"));
        shop.setStatus(((Number) map.get("status")).intValue());
        shop.setRemark((String) map.get("remark"));
        
        // 设备统计
        Object deviceCount = map.get("device_count");
        shop.setDeviceCount(deviceCount != null ? ((Number) deviceCount).intValue() : 0);
        
        Object onlineCount = map.get("online_count");
        shop.setOnlineCount(onlineCount != null ? ((Number) onlineCount).intValue() : 0);
        
        fillShopLabels(shop);
        
        return shop;
    }

    @Override
    public List<ShopSelectVO> getAllEnabledShops() {
        List<Map<String, Object>> maps = shopMapper.selectAllEnabledShops();
        return maps.stream().map(m -> ShopSelectVO.builder()
                .id((Long) m.get("id"))
                .name((String) m.get("name"))
                .address((String) m.get("address"))
                .contactName((String) m.get("contact_name"))
                .contactPhone((String) m.get("contact_phone"))
                .erpShopId((Long) m.get("erp_shop_id"))
                .build()
        ).toList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Shop createShop(Shop shop) {
        // 生成门店编码
        if (!StringUtils.hasText(shop.getShopCode())) {
            shop.setShopCode("SH" + System.currentTimeMillis());
        }
        
        // 默认状态
        if (shop.getStatus() == null) {
            shop.setStatus(CommonStatus.ENABLED.getCode());
        }
        
        shop.setCreateTime(LocalDateTime.now());
        shop.setUpdateTime(LocalDateTime.now());
        
        this.save(shop);
        
        fillShopLabels(shop);
        
        log.info("创建门店成功: id={}, name={}", shop.getId(), shop.getName());
        
        return shop;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Shop updateShop(Shop shop) {
        Shop existShop = this.getById(shop.getId());
        if (existShop == null) {
            throw new BusinessException(404, "门店不存在");
        }
        
        shop.setUpdateTime(LocalDateTime.now());
        
        this.updateById(shop);
        
        Shop updated = this.getById(shop.getId());
        fillShopStats(updated);
        fillShopLabels(updated);
        
        log.info("更新门店成功: id={}, name={}", shop.getId(), shop.getName());
        
        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean toggleStatus(Long id, Integer status) {
        Shop shop = this.getById(id);
        if (shop == null) {
            throw new BusinessException(404, "门店不存在");
        }
        
        LambdaUpdateWrapper<Shop> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Shop::getId, id)
               .set(Shop::getStatus, status)
               .set(Shop::getUpdateTime, LocalDateTime.now());
        
        boolean result = this.update(wrapper);
        
        if (result) {
            log.info("切换门店状态成功: id={}, status={}", id, status);
        }
        
        return result;
    }

    @Override
    public ShopStatisticsVO getStatistics() {
        // 总门店数
        long total = this.count();

        // 启用门店数
        long enabled = this.lambdaQuery()
                .eq(Shop::getStatus, CommonStatus.ENABLED.getCode())
                .count();

        // 禁用门店数
        long disabled = total - enabled;

        // 总设备数
        long totalDevices = deviceService.count();

        // 在线设备数
        long onlineDevices = deviceService.lambdaQuery()
                .eq(Device::getStatus, DeviceConstants.STATUS_ONLINE)
                .count();

        return ShopStatisticsVO.builder()
                .total(total)
                .enabled(enabled)
                .disabled(disabled)
                .totalDevices(totalDevices)
                .onlineDevices(onlineDevices)
                .build();
    }

    @Override
    public List<ShopDeviceVO> getDevicesByShopId(Long shopId) {
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Device::getShopId, shopId)
               .orderByDesc(Device::getCreateTime);
        
        List<Device> devices = deviceService.list(wrapper);
        
        return devices.stream().map(device -> ShopDeviceVO.builder()
                .id(device.getId())
                .deviceId(device.getDeviceId())
                .name(device.getName())
                .status(device.getStatus())
                .createTime(device.getCreateTime())
                .build()
        ).toList();
    }

    @Override
    public boolean linkDevice(Long shopId, Long deviceId) {
        // 检查门店是否存在
        Shop shop = this.getById(shopId);
        if (shop == null) {
            throw new BusinessException(404, "门店不存在");
        }
        
        // 检查设备是否存在
        Device device = deviceService.getById(deviceId);
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }
        
        // 如果设备已关联到其他门店，先解除关联
        if (device.getShopId() != null && !device.getShopId().equals(shopId)) {
            log.info("设备已关联到其他门店，将解除原关联: deviceId={}, oldShopId={}", deviceId, device.getShopId());
        }
        
        // 关联设备到门店
        device.setShopId(shopId);
        device.setUpdateTime(LocalDateTime.now());
        boolean result = deviceService.updateById(device);
        
        if (result) {
            log.info("设备关联门店成功: deviceId={}, shopId={}", deviceId, shopId);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchLinkDevices(Long shopId, List<Long> deviceIds) {
        if (deviceIds == null || deviceIds.isEmpty()) {
            return 0;
        }
        
        // 检查门店是否存在
        Shop shop = this.getById(shopId);
        if (shop == null) {
            throw new BusinessException(404, "门店不存在");
        }
        
        // 批量更新设备的门店关联
        LambdaUpdateWrapper<Device> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(Device::getId, deviceIds)
               .set(Device::getShopId, shopId)
               .set(Device::getUpdateTime, LocalDateTime.now());
        
        boolean success = deviceService.update(wrapper);
        int count = success ? deviceIds.size() : 0;
        
        log.info("批量关联设备完成: shopId={}, 总数={}, 成功={}", shopId, deviceIds.size(), count);
        return count;
    }

    @Override
    public boolean unlinkDevice(Long shopId, Long deviceId) {
        // 检查设备是否属于该门店
        Device device = deviceService.getById(deviceId);
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }
        
        if (!shopId.equals(device.getShopId())) {
            throw new BusinessException(400, "该设备不属于当前门店");
        }
        
        // 解除关联
        device.setShopId(null);
        device.setUpdateTime(LocalDateTime.now());
        boolean result = deviceService.updateById(device);
        
        if (result) {
            log.info("设备解除门店关联成功: deviceId={}, shopId={}", deviceId, shopId);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchUnlinkDevices(Long shopId, List<Long> deviceIds) {
        if (deviceIds == null || deviceIds.isEmpty()) {
            return 0;
        }
        
        // 批量解除设备关联
        LambdaUpdateWrapper<Device> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Device::getShopId, shopId)
               .in(Device::getId, deviceIds)
               .set(Device::getShopId, null)
               .set(Device::getUpdateTime, LocalDateTime.now());
        
        boolean success = deviceService.update(wrapper);
        int count = success ? deviceIds.size() : 0;
        
        log.info("批量解除关联完成: shopId={}, 总数={}, 成功={}", shopId, deviceIds.size(), count);
        return count;
    }

    /**
     * 填充门店设备统计信息
     */
    private void fillShopStats(Shop shop) {
        // 统计该门店的设备数量
        long deviceCount = deviceService.lambdaQuery()
                .eq(Device::getShopId, shop.getId())
                .count();
        shop.setDeviceCount((int) deviceCount);
        
        // 统计在线设备数量
        long onlineCount = deviceService.lambdaQuery()
                .eq(Device::getShopId, shop.getId())
                .eq(Device::getStatus, DeviceConstants.STATUS_ONLINE)
                .count();
        shop.setOnlineCount((int) onlineCount);
    }

    /**
     * 填充门店状态标签
     */
    private void fillShopLabels(Shop shop) {
        if (shop.getStatus() != null) {
            com.haha.common.vo.StatusLabel label = 
                com.haha.common.utils.EntityLabelUtils.getStatusLabel("common", shop.getStatus());
            shop.setStatusLabel(label.getLabel());
            shop.setStatusColor(label.getColor());
        }
    }
}
