package com.haha.service.impl;

import cn.dev33.satoken.stp.StpUtil;
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.RedisConstants;
import com.haha.common.enums.CommonStatus;
import com.haha.common.exception.BusinessException;
import com.haha.common.vo.LoginVO;
import com.haha.common.vo.Result;
import com.haha.common.vo.UserVO;
import com.haha.entity.Replenisher;
import com.haha.entity.ReplenisherDevice;
import com.haha.entity.dto.ReplenisherCreateDTO;
import com.haha.entity.dto.ReplenisherQueryDTO;
import com.haha.entity.dto.ReplenisherUpdateDTO;
import com.haha.mapper.ReplenisherDeviceMapper;
import com.haha.mapper.ReplenisherMapper;
import com.haha.service.ReplenisherService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 补货员服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReplenisherServiceImpl extends ServiceImpl<ReplenisherMapper, Replenisher> implements ReplenisherService {

    private final ReplenisherMapper replenisherMapper;
    private final ReplenisherDeviceMapper replenisherDeviceMapper;
    private final RestTemplate restTemplate;
    private final StringRedisTemplate stringRedisTemplate;

    @Value("${wechat.admin-miniapp.app-id}")
    private String adminMiniappAppId;

    @Value("${wechat.admin-miniapp.secret}")
    private String adminMiniappSecret;

    @Override
    public IPage<Replenisher> getPage(ReplenisherQueryDTO queryDTO) {
        queryDTO.validate();

        Page<Replenisher> page = new Page<>(queryDTO.getPage(), queryDTO.getPageSize());
        IPage<Replenisher> result = replenisherMapper.selectWithDeviceCount(page, queryDTO.getKeyword(), queryDTO.getStatus());

        // 填充状态标签
        for (Replenisher r : result.getRecords()) {
            fillStatusLabel(r);
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Replenisher createReplenisher(ReplenisherCreateDTO dto) {
        // 检查手机号是否已存在
        if (StringUtils.hasText(dto.getPhone())) {
            LambdaQueryWrapper<Replenisher> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Replenisher::getPhone, dto.getPhone());
            if (this.count(wrapper) > 0) {
                throw new BusinessException(400, "该手机号已被其他补货员使用");
            }
        }

        Replenisher replenisher = new Replenisher();
        replenisher.setName(dto.getName());
        replenisher.setPhone(dto.getPhone());
        replenisher.setEmployeeId(dto.getEmployeeId());
        replenisher.setStatus(CommonStatus.ENABLED.getCode());
        replenisher.setTotalTasks(0);
        replenisher.setCreateTime(LocalDateTime.now());
        replenisher.setUpdateTime(LocalDateTime.now());

        this.save(replenisher);

        log.info("创建补货员成功: id={}, name={}", replenisher.getId(), dto.getName());

        fillStatusLabel(replenisher);
        return replenisher;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Replenisher updateReplenisher(Long id, ReplenisherUpdateDTO dto) {
        Replenisher replenisher = this.getById(id);
        if (replenisher == null) {
            throw new BusinessException(404, "补货员不存在");
        }

        // 检查手机号是否与其他补货员重复
        if (StringUtils.hasText(dto.getPhone())) {
            LambdaQueryWrapper<Replenisher> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Replenisher::getPhone, dto.getPhone())
                    .ne(Replenisher::getId, id);
            if (this.count(wrapper) > 0) {
                throw new BusinessException(400, "该手机号已被其他补货员使用");
            }
        }

        if (StringUtils.hasText(dto.getName())) {
            replenisher.setName(dto.getName());
        }
        if (StringUtils.hasText(dto.getPhone())) {
            replenisher.setPhone(dto.getPhone());
        }
        if (StringUtils.hasText(dto.getEmployeeId())) {
            replenisher.setEmployeeId(dto.getEmployeeId());
        }
        if (dto.getStatus() != null) {
            replenisher.setStatus(dto.getStatus());
        }
        replenisher.setUpdateTime(LocalDateTime.now());

        this.updateById(replenisher);

        log.info("更新补货员成功: id={}, name={}", id, replenisher.getName());

        fillStatusLabel(replenisher);
        return replenisher;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id, Integer status) {
        Replenisher replenisher = this.getById(id);
        if (replenisher == null) {
            throw new BusinessException(404, "补货员不存在");
        }

        replenisher.setStatus(status);
        replenisher.setUpdateTime(LocalDateTime.now());
        this.updateById(replenisher);

        log.info("更新补货员状态: id={}, status={}", id, status);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteReplenisher(Long id) {
        Replenisher replenisher = this.getById(id);
        if (replenisher == null) {
            throw new BusinessException(404, "补货员不存在");
        }

        // 级联删除设备绑定
        replenisherDeviceMapper.deleteByReplenisherId(id);

        // 删除补货员
        this.removeById(id);

        log.info("删除补货员成功: id={}, name={}", id, replenisher.getName());
    }

    @Override
    public Replenisher getReplenisherDetail(Long id) {
        Replenisher replenisher = this.getById(id);
        if (replenisher == null) {
            return null;
        }

        // 填充设备绑定数
        replenisher.setBoundDeviceCount(replenisherMapper.countBoundDevices(id));
        fillStatusLabel(replenisher);

        return replenisher;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int bindDevices(Long replenisherId, List<String> deviceIds) {
        Replenisher replenisher = this.getById(replenisherId);
        if (replenisher == null) {
            throw new BusinessException(404, "补货员不存在");
        }

        if (deviceIds == null || deviceIds.isEmpty()) {
            return 0;
        }

        List<ReplenisherDevice> toAdd = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();

        for (String deviceId : deviceIds) {
            int count = replenisherDeviceMapper.countByReplenisherIdAndDeviceId(replenisherId, deviceId);
            if (count > 0) {
                log.warn("绑定已存在，跳过: replenisherId={}, deviceId={}", replenisherId, deviceId);
                continue;
            }

            ReplenisherDevice rd = new ReplenisherDevice();
            rd.setReplenisherId(replenisherId);
            rd.setDeviceId(deviceId);
            rd.setSource("MANUAL");
            rd.setCreateTime(now);
            toAdd.add(rd);
        }

        if (!toAdd.isEmpty()) {
            replenisherDeviceMapper.batchInsertIgnore(toAdd);
        }

        log.info("绑定设备到补货员: replenisherId={}, 请求={}, 成功={}", replenisherId, deviceIds.size(), toAdd.size());
        return toAdd.size();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unbindDevice(Long replenisherId, String deviceId) {
        LambdaQueryWrapper<ReplenisherDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ReplenisherDevice::getReplenisherId, replenisherId)
                .eq(ReplenisherDevice::getDeviceId, deviceId);

        replenisherDeviceMapper.delete(wrapper);

        log.info("解绑补货员设备: replenisherId={}, deviceId={}", replenisherId, deviceId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchBindDevices(List<Long> replenisherIds, List<String> deviceIds) {
        if (replenisherIds == null || replenisherIds.isEmpty() || deviceIds == null || deviceIds.isEmpty()) {
            return 0;
        }

        int total = 0;
        for (Long replenisherId : replenisherIds) {
            total += bindDevices(replenisherId, deviceIds);
        }

        return total;
    }

    @Override
    public List<String> getBoundDeviceIds(Long replenisherId) {
        return replenisherDeviceMapper.selectDeviceIdsByReplenisherId(replenisherId);
    }

    @Override
    public List<Replenisher> getReplenishersByDeviceId(String deviceId) {
        List<Replenisher> list = replenisherMapper.selectByDeviceId(deviceId);
        for (Replenisher r : list) {
            fillStatusLabel(r);
        }
        return list;
    }

    @Override
    public List<Replenisher> getReplenishersByShopId(Long shopId) {
        List<Replenisher> list = replenisherMapper.selectByShopId(shopId);
        for (Replenisher r : list) {
            fillStatusLabel(r);
        }
        return list;
    }

    @Override
    public List<Replenisher> searchByKeyword(String keyword) {
        return replenisherMapper.searchByKeyword(keyword);
    }

    @Override
    public Result<LoginVO> loginByWechat(String code) {
        try {
            log.info("[补货员] 微信静默登录 - code: {}",
                    code != null ? code.substring(0, Math.min(8, code.length())) + "..." : "null");

            // 1. 通过code获取openid
            String openid = getWechatOpenid(code);
            if (openid == null || openid.isEmpty()) {
                log.warn("[补货员] 获取openid失败 - code: {}",
                        code != null ? code.substring(0, Math.min(8, code.length())) + "..." : "null");
                return Result.error(400, "获取用户标识失败，请重试");
            }

            // 2. 根据openid查找补货员（仅限已绑定微信的账号）
            LambdaQueryWrapper<Replenisher> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Replenisher::getWechatOpenid, openid);
            Replenisher replenisher = this.getOne(wrapper);

            if (replenisher == null) {
                // 不允许自动注册：补货员必须先由后台创建并通过扫码绑定微信
                log.warn("[补货员] 微信登录 - openid未绑定任何补货员账号: openid={}",
                        openid.substring(0, Math.min(10, openid.length())) + "...");
                return Result.error(403, "该微信未绑定补货员账号，请联系管理员获取绑定二维码");
            }

            // 3. 检查状态
            if (replenisher.getStatus() == null || replenisher.getStatus() == CommonStatus.DISABLED.getCode()) {
                log.warn("[补货员] 账号已被禁用: id={}, openid={}", replenisher.getId(), openid);
                return Result.error(403, "您的账号已被禁用，请联系管理员");
            }

            // 4. 生成token
            StpUtil.login(replenisher.getId());
            StpUtil.getTokenSession().set("userType", "REPLENISHER");
            String token = StpUtil.getTokenValue();

            log.info("[补货员] 微信登录成功: id={}, name={}", replenisher.getId(), replenisher.getName());

            // 5. 构建返回结果
            UserVO userVO = UserVO.builder()
                    .id(replenisher.getId())
                    .nickname(replenisher.getName())
                    .avatar(replenisher.getAvatar())
                    .phone(replenisher.getPhone())
                    .build();

            LoginVO loginVO = LoginVO.builder()
                    .token(token)
                    .userInfo(userVO)
                    .build();

            return Result.success("登录成功", loginVO);

        } catch (Exception e) {
            log.error("[补货员] 微信静默登录异常", e);
            return Result.error(500, "登录失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String generateBindingCode(Long replenisherId) {
        // 1. 检查补货员是否存在
        Replenisher replenisher = this.getById(replenisherId);
        if (replenisher == null) {
            throw new BusinessException(404, "补货员不存在");
        }

        // 2. 如果已经绑定了微信，不允许再次生成绑定码
        if (StringUtils.hasText(replenisher.getWechatOpenid())) {
            throw new BusinessException(400, "该补货员已绑定微信，无需重新绑定");
        }

        // 3. 生成UUID绑定码并存入Redis（24小时有效）
        String bindingCode = UUID.randomUUID().toString().replace("-", "").substring(0, 24).toUpperCase();
        String redisKey = String.format(RedisConstants.REPLENISHER_BIND_CODE_KEY, bindingCode);
        stringRedisTemplate.opsForValue().set(redisKey, String.valueOf(replenisherId), 24, TimeUnit.HOURS);

        log.info("[补货员] 生成绑定码: replenisherId={}, bindingCode={}", replenisherId, bindingCode);

        return bindingCode;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<LoginVO> bindWechat(String bindingCode, String wechatCode) {
        try {
            log.info("[补货员] 扫码绑定微信 - bindingCode: {}",
                    bindingCode != null ? bindingCode.substring(0, Math.min(8, bindingCode.length())) + "..." : "null");

            // 1. 验证绑定码
            String redisKey = String.format(RedisConstants.REPLENISHER_BIND_CODE_KEY, bindingCode);
            String replenisherIdStr = stringRedisTemplate.opsForValue().get(redisKey);
            if (replenisherIdStr == null || replenisherIdStr.isEmpty()) {
                log.warn("[补货员] 绑定码无效或已过期: bindingCode={}", bindingCode);
                return Result.error(400, "绑定码无效或已过期，请联系管理员重新生成");
            }

            Long replenisherId = Long.valueOf(replenisherIdStr);

            // 2. 获取微信openid
            String openid = getWechatOpenid(wechatCode);
            if (openid == null || openid.isEmpty()) {
                log.warn("[补货员] 绑定 - 获取openid失败");
                return Result.error(400, "获取微信标识失败，请重试");
            }

            // 3. 检查openid是否已被其他补货员绑定
            LambdaQueryWrapper<Replenisher> openidCheck = new LambdaQueryWrapper<>();
            openidCheck.eq(Replenisher::getWechatOpenid, openid)
                    .ne(Replenisher::getId, replenisherId);
            if (this.count(openidCheck) > 0) {
                log.warn("[补货员] 绑定 - openid已被其他补货员绑定: openid={}", openid);
                return Result.error(400, "该微信已绑定其他补货员账号");
            }

            // 4. 检查补货员是否存在
            Replenisher replenisher = this.getById(replenisherId);
            if (replenisher == null) {
                log.warn("[补货员] 绑定 - 补货员不存在: id={}", replenisherId);
                return Result.error(404, "补货员不存在");
            }

            // 5. 如果已绑定微信且不是同一个，拒绝
            if (StringUtils.hasText(replenisher.getWechatOpenid()) && !openid.equals(replenisher.getWechatOpenid())) {
                log.warn("[补货员] 绑定 - 补货员已绑定其他微信: id={}", replenisherId);
                return Result.error(400, "该补货员已绑定其他微信账号");
            }

            // 6. 绑定微信openid + 激活账号
            replenisher.setWechatOpenid(openid);
            replenisher.setStatus(CommonStatus.ENABLED.getCode());
            replenisher.setUpdateTime(LocalDateTime.now());
            this.updateById(replenisher);

            // 7. 删除已使用的绑定码
            stringRedisTemplate.delete(redisKey);

            log.info("[补货员] 绑定微信成功: id={}, name={}, openid={}",
                    replenisherId, replenisher.getName(),
                    openid.substring(0, Math.min(10, openid.length())) + "...");

            // 8. 登录
            StpUtil.login(replenisher.getId());
            StpUtil.getTokenSession().set("userType", "REPLENISHER");
            String token = StpUtil.getTokenValue();

            UserVO userVO = UserVO.builder()
                    .id(replenisher.getId())
                    .nickname(replenisher.getName())
                    .avatar(replenisher.getAvatar())
                    .phone(replenisher.getPhone())
                    .build();

            LoginVO loginVO = LoginVO.builder()
                    .token(token)
                    .userInfo(userVO)
                    .build();

            return Result.success("绑定并登录成功", loginVO);

        } catch (Exception e) {
            log.error("[补货员] 扫码绑定微信异常", e);
            return Result.error(500, "绑定失败：" + e.getMessage());
        }
    }

    /**
     * 通过微信登录凭证code获取openid
     */
    private String getWechatOpenid(String code) {
        try {
            log.info("[微信API-管理端] 开始获取openid - appid: {}, code: {}",
                    adminMiniappAppId,
                    code != null ? code.substring(0, Math.min(10, code.length())) + "..." : "null");

            String url = String.format(
                    "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                    adminMiniappAppId, adminMiniappSecret, code
            );

            log.debug("[微信API-管理端] 请求URL: {}", url.replace(adminMiniappSecret, "***"));

            String response = restTemplate.getForObject(url, String.class);
            log.info("[微信API-管理端] 获取openid响应: {}", response);

            if (response != null && !response.isEmpty()) {
                try {
                    com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
                    java.util.Map<String, Object> result = objectMapper.readValue(response, java.util.Map.class);

                    if (result.containsKey("errcode")) {
                        Integer errcode = (Integer) result.get("errcode");
                        String errmsg = (String) result.get("errmsg");
                        log.error("[微信API-管理端] 获取openid失败 - errcode: {}, errmsg: {}", errcode, errmsg);
                        return null;
                    }

                    if (result.containsKey("openid")) {
                        String openid = (String) result.get("openid");
                        log.info("[微信API-管理端] 获取openid成功 - openid: {}",
                                openid != null ? openid.substring(0, Math.min(10, openid.length())) + "..." : "null");
                        return openid;
                    }
                } catch (Exception parseEx) {
                    log.error("[微信API-管理端] 解析响应JSON失败", parseEx);
                }
            }

            log.error("[微信API-管理端] 获取openid失败 - response: {}", response);
            return null;
        } catch (Exception e) {
            log.error("[微信API-管理端] 调用jscode2session异常", e);
            return null;
        }
    }

    /**
     * 填充状态标签
     */
    private void fillStatusLabel(Replenisher r) {
        if (r.getStatus() != null) {
            if (r.getStatus() == CommonStatus.ENABLED.getCode()) {
                r.setStatusLabel("正常");
                r.setStatusColor("success");
            } else {
                r.setStatusLabel("禁用");
                r.setStatusColor("danger");
            }
        }
    }
}
