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.exception.BusinessException;
import com.haha.entity.Device;
import com.haha.entity.ErpShop;
import com.haha.mapper.DeviceMapper;
import com.haha.mapper.ErpShopMapper;
import com.haha.service.ErpShopService;
import com.qdb.sdk.QdbClient;
import com.qdb.sdk.QdbException;
import com.qdb.sdk.model.request.ShopQueryRequest;
import com.qdb.sdk.model.response.QdbResponse;
import com.qdb.sdk.model.response.ShopInfo;
import com.qdb.sdk.model.response.ShopPageResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class ErpShopServiceImpl extends ServiceImpl<ErpShopMapper, ErpShop> implements ErpShopService {

    private final DeviceMapper deviceMapper;

    @Autowired(required = false)
    private QdbClient qdbClient;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Async("taskExecutor")
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncFromErp() {
        if (qdbClient == null) {
            throw new BusinessException(500, "QdbClient 未配置，无法同步ERP店铺数据");
        }

        int pageNo = 1;
        int pageSize = 50;
        boolean hasMore = true;
        int syncedCount = 0;
        int filteredCount = 0;

        while (hasMore) {
            ShopQueryRequest request = ShopQueryRequest.builder()
                    .pageIndex(pageNo)
                    .pageSize(pageSize)
                    .build();

            try {
                QdbResponse<ShopPageResult> response = qdbClient.getShopApi().queryShopInfo(request);
                ShopPageResult pageResult = response.getData();

                if (pageResult == null || pageResult.getData() == null || pageResult.getData().isEmpty()) {
                    hasMore = false;
                    break;
                }

                for (ShopInfo shopInfo : pageResult.getData()) {
                    if (shopInfo.getShopName() == null
                            || !shopInfo.getShopName().contains("自助售卖机")) {
                        filteredCount++;
                        continue;
                    }
                    upsertErpShop(shopInfo);
                    syncedCount++;
                }

                Integer total = pageResult.getTotal();
                if (total != null && pageNo * pageSize >= total) {
                    hasMore = false;
                } else if (pageResult.getData().size() < pageSize) {
                    hasMore = false;
                } else {
                    pageNo++;
                }

            } catch (QdbException e) {
                log.error("同步ERP店铺失败: pageNo={}, error={}", pageNo, e.getMessage());
                throw new BusinessException(500, "ERP店铺同步失败: " + e.getMessage());
            }
        }

        log.info("ERP店铺同步完成: 协同步 {} 条, 过滤 {} 条", syncedCount, filteredCount);
    }

    @Override
    public IPage<ErpShop> listAll(String keyword, Integer boundStatus, Integer bindEnabled, int page, int pageSize) {
        LambdaQueryWrapper<ErpShop> wrapper = new LambdaQueryWrapper<ErpShop>()
                .eq(ErpShop::getStatus, 1);
        if (bindEnabled != null) {
            wrapper.eq(ErpShop::getBindEnabled, bindEnabled);
        }
        if (StringUtils.hasText(keyword)) {
            wrapper.and(w -> w
                    .like(ErpShop::getShopName, keyword)
                    .or()
                    .like(ErpShop::getNickName, keyword));
        }

        // 已绑定/未绑定筛选：通过 t_device.erp_shop_id 关联判断
        if (boundStatus != null) {
            List<Device> boundDevices = deviceMapper.selectList(new LambdaQueryWrapper<Device>()
                    .isNotNull(Device::getErpShopId)
                    .select(Device::getErpShopId));
            Set<Long> boundErpShopIds = boundDevices.stream()
                    .map(Device::getErpShopId).filter(Objects::nonNull).collect(Collectors.toSet());

            if (boundStatus == 1) {
                // 已绑定
                if (boundErpShopIds.isEmpty()) {
                    // 没有任何设备已绑定，返回空页
                    return new Page<>(page, pageSize);
                }
                wrapper.in(ErpShop::getErpShopId, boundErpShopIds);
            } else {
                // 未绑定
                if (!boundErpShopIds.isEmpty()) {
                    wrapper.notIn(ErpShop::getErpShopId, boundErpShopIds);
                }
            }
        }

        return page(new Page<>(page, pageSize), wrapper.orderByAsc(ErpShop::getShopName));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindDevice(Long deviceId, Long erpShopId) {
        Device device = deviceMapper.selectById(deviceId);
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }

        ErpShop erpShop = getOne(new LambdaQueryWrapper<ErpShop>()
                .eq(ErpShop::getErpShopId, erpShopId));
        if (erpShop == null) {
            throw new BusinessException(404, "ERP店铺不存在，请先同步ERP店铺数据");
        }
        if (erpShop.getBindEnabled() != null && erpShop.getBindEnabled() == 0) {
            throw new BusinessException(400, "该ERP店铺已被设置为不允许绑定");
        }

        List<Device> boundDevices = deviceMapper.selectList(new LambdaQueryWrapper<Device>()
                .eq(Device::getErpShopId, erpShopId));
        if (!boundDevices.isEmpty() && !boundDevices.get(0).getId().equals(deviceId)) {
            throw new BusinessException(400, "该ERP店铺已绑定到设备: " + boundDevices.get(0).getDeviceId());
        }

        device.setErpShopId(erpShopId);
        device.setUpdateTime(LocalDateTime.now());
        deviceMapper.updateById(device);

        log.info("设备绑定ERP店铺: deviceId={}, erpShopId={}, erpShopName={}",
                device.getDeviceId(), erpShopId, erpShop.getShopName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unbindDevice(Long deviceId) {
        Device device = deviceMapper.selectById(deviceId);
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }

        deviceMapper.update(null, new LambdaUpdateWrapper<Device>()
                .set(Device::getErpShopId, null)
                .set(Device::getUpdateTime, LocalDateTime.now())
                .eq(Device::getId, deviceId));

        log.info("设备解绑ERP店铺: deviceId={}", device.getDeviceId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchUpdateBindEnabled(List<Long> erpShopIds, int bindEnabled) {
        if (erpShopIds == null || erpShopIds.isEmpty()) {
            return 0;
        }
        // 禁止绑定时，先解绑已关联的设备
        if (bindEnabled == 0) {
            int unboundCount = deviceMapper.update(null, new LambdaUpdateWrapper<Device>()
                    .in(Device::getErpShopId, erpShopIds)
                    .set(Device::getErpShopId, null)
                    .set(Device::getUpdateTime, LocalDateTime.now()));
            log.info("禁止绑定前解绑设备: {} 台", unboundCount);
        }
        boolean updated = update(new LambdaUpdateWrapper<ErpShop>()
                .in(ErpShop::getErpShopId, erpShopIds)
                .set(ErpShop::getBindEnabled, bindEnabled)
                .set(ErpShop::getUpdateTime, LocalDateTime.now()));
        int count = updated ? erpShopIds.size() : 0;
        log.info("批量修改允许绑定标识: ids={}, bindEnabled={}, count={}", erpShopIds, bindEnabled, count);
        return count;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int unbindAll() {
        // 查询所有已绑定 ERP 店铺的设备数量
        long boundCount = deviceMapper.selectCount(new LambdaQueryWrapper<Device>()
                .isNotNull(Device::getErpShopId));
        if (boundCount == 0) {
            return 0;
        }

        // 批量将所有设备的 erpShopId 置为 null
        deviceMapper.update(null, new LambdaUpdateWrapper<Device>()
                .isNotNull(Device::getErpShopId)
                .set(Device::getErpShopId, null)
                .set(Device::getUpdateTime, LocalDateTime.now()));

        log.info("一键解绑完成: 共解绑 {} 台设备", boundCount);
        return (int) boundCount;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Integer> autoBind() {
        List<ErpShop> erpShopList = list(new LambdaQueryWrapper<ErpShop>()
                .eq(ErpShop::getStatus, 1)
                .ne(ErpShop::getBindEnabled, 0)); // 排除不允许绑定的店铺
        if (erpShopList.isEmpty()) {
            Map<String, Integer> empty = new HashMap<>();
            empty.put("bound", 0);
            empty.put("skipped", 0);
            return empty;
        }

        // 1. 收集所有 shopCode → erpShopId 映射 (shopCode 即设备ID)
        Map<String, Long> shopCodeToErpId = new LinkedHashMap<>();
        for (ErpShop erp : erpShopList) {
            if (StringUtils.hasText(erp.getShopCode())) {
                shopCodeToErpId.put(erp.getShopCode(), erp.getErpShopId());
            }
        }

        // 2. 批量查已绑定的设备
        List<Long> allErpShopIds = erpShopList.stream().map(ErpShop::getErpShopId).toList();
        Set<Long> boundErpIds = new HashSet<>(deviceMapper.selectList(new LambdaQueryWrapper<Device>()
                .in(Device::getErpShopId, allErpShopIds)
                .isNotNull(Device::getErpShopId))
                .stream().map(Device::getErpShopId).toList());

        // 3. 过滤掉已绑定的，剩下的按 deviceId 批量查设备
        List<String> targetDeviceIds = new ArrayList<>();
        for (Map.Entry<String, Long> e : shopCodeToErpId.entrySet()) {
            if (!boundErpIds.contains(e.getValue())) {
                targetDeviceIds.add(e.getKey());
            }
        }
        int alreadyBoundSkip = shopCodeToErpId.size() - targetDeviceIds.size();

        Map<String, Long> deviceIdToDbId = new LinkedHashMap<>();
        for (int i = 0; i < targetDeviceIds.size(); i += 100) {
            int end = Math.min(i + 100, targetDeviceIds.size());
            List<String> batch = targetDeviceIds.subList(i, end);
            List<Device> devices = deviceMapper.selectList(new LambdaQueryWrapper<Device>()
                    .in(Device::getDeviceId, batch));
            for (Device d : devices) {
                deviceIdToDbId.put(d.getDeviceId(), d.getId());
            }
        }

        // 4. 唯一匹配的收集起来准备批量 UPDATE
        List<Long> bindDbIds = new ArrayList<>();
        List<Long> bindErpIds = new ArrayList<>();
        int skipped = alreadyBoundSkip;

        for (String deviceId : targetDeviceIds) {
            Long dbId = deviceIdToDbId.get(deviceId);
            if (dbId != null && dbId > 0) {
                bindDbIds.add(dbId);
                bindErpIds.add(shopCodeToErpId.get(deviceId));
            } else {
                skipped++;
            }
        }

        // 5. 批量 UPDATE（CASE WHEN，100条一批）
        int bound = 0;
        for (int i = 0; i < bindDbIds.size(); i += 100) {
            int end = Math.min(i + 100, bindDbIds.size());
            List<Long> batchIds = bindDbIds.subList(i, end);
            List<Long> batchErpIds = bindErpIds.subList(i, end);

            StringBuilder sql = new StringBuilder(
                    "UPDATE t_device SET erp_shop_id = CASE id ");
            for (int j = 0; j < batchIds.size(); j++) {
                sql.append("WHEN ").append(batchIds.get(j))
                   .append(" THEN ").append(batchErpIds.get(j)).append(" ");
            }
            sql.append("END, update_time = NOW() WHERE id IN (");
            for (int j = 0; j < batchIds.size(); j++) {
                if (j > 0) sql.append(",");
                sql.append(batchIds.get(j));
            }
            sql.append(")");

            bound += jdbcTemplate.update(sql.toString());
        }

        log.info("一键自动绑定完成: 成功 {} 条, 跳过 {} 条", bound, skipped);
        Map<String, Integer> result = new HashMap<>();
        result.put("bound", bound);
        result.put("skipped", skipped);
        return result;
    }

    private void upsertErpShop(ShopInfo info) {
        ErpShop existing = getOne(new LambdaQueryWrapper<ErpShop>()
                .eq(ErpShop::getErpShopId, info.getShopId()));

        if (existing != null) {
            existing.setOutShopId(info.getOutShopId());
            existing.setShopName(info.getShopName());
            existing.setShopPlatformCode(info.getShopPlatformCode());
            existing.setNickName(info.getNickName());
            existing.setShopCode(info.getShopCode());
            existing.setPlatformShopId(info.getPlatformShopId());
            existing.setAccessTokenExpiredTime(info.getAccessTokenExpiredTime());
            existing.setServiceExpirationTime(info.getServiceExpirationTime());
            existing.setAuthorizationFlag(info.getAuthorizationFlag());
            existing.setStatus(info.getStatus() != null ? Integer.parseInt(info.getStatus()) : 1);
            existing.setUpdateTime(LocalDateTime.now());
            updateById(existing);
        } else {
            ErpShop erpShop = new ErpShop();
            erpShop.setErpShopId(info.getShopId());
            erpShop.setOutShopId(info.getOutShopId());
            erpShop.setShopName(info.getShopName());
            erpShop.setShopPlatformCode(info.getShopPlatformCode());
            erpShop.setNickName(info.getNickName());
            erpShop.setShopCode(info.getShopCode());
            erpShop.setPlatformShopId(info.getPlatformShopId());
            erpShop.setAccessTokenExpiredTime(info.getAccessTokenExpiredTime());
            erpShop.setServiceExpirationTime(info.getServiceExpirationTime());
            erpShop.setAuthorizationFlag(info.getAuthorizationFlag());
            erpShop.setStatus(info.getStatus() != null ? Integer.parseInt(info.getStatus()) : 1);
            erpShop.setBindEnabled(1); // 新店铺默认允许绑定
            erpShop.setCreateTime(LocalDateTime.now());
            erpShop.setUpdateTime(LocalDateTime.now());
            save(erpShop);
        }
    }
}
