package com.wecloud.im.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.nacos.api.exception.NacosException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wecloud.im.balance.WsInstance;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.param.ImTokenVerify;
import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientLoginService;
import com.wecloud.im.service.ImClientService;
import com.wecloud.im.vo.TokenVo;
import io.geekidea.springbootplus.config.properties.JwtProperties;
import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.shiro.cache.AppLoginRedisService;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;

@Service
@Slf4j
public class ImClientLoginServiceImpl implements ImClientLoginService {

//    @Autowired
//    private RedisUtils redisUtils;

//    @Autowired
//    private StringRedisTemplate redisTemplate;

    private static JwtProperties jwtProperties;
    @Autowired
    private ImApplicationService imApplicationService;
    @Autowired
    private ImClientService imClientService;
    @Autowired
    private WsInstance wsInstance;
    @Autowired
    private AppLoginRedisService appLoginRedisService;

    public ImClientLoginServiceImpl(JwtProperties jwtProperties) {
        ImClientLoginServiceImpl.jwtProperties = jwtProperties;
    }


    /**
     * 根据客户方生成签名字符串 验证通过则下发token
     *
     * @param imTokenVerify
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<TokenVo> verifySign(ImTokenVerify imTokenVerify) throws NacosException {

        //  根据appKey从数据库查询密钥
        ImApplication imApplication = imApplicationService.getOneByAppKey(imTokenVerify.getAppKey());

        if (imApplication == null) {
            log.info("imApplication == null,getAppKey:" + imTokenVerify.getAppKey());
            return ApiResult.result(ApiCode.FAIL, null);
        }

        // 生成以数据库为准的签名
        String secret = imApplication.getAppSecret();
        String mySign = new MD5().digestHex(imTokenVerify.getTimestamp() + imTokenVerify.getClientId() + imApplication.getAppKey() + secret);

        // 验证签名
        if (!mySign.equals(imTokenVerify.getSign())) {
            log.info("sign不一致" + mySign);
            return ApiResult.result(ApiCode.FAIL, null);
        }

        // 判断client是否存在
        ImClient imClient = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                .eq(ImClient::getFkAppid, imApplication.getId())
                .eq(ImClient::getClientId, imTokenVerify.getClientId()));

        if (imClient == null) {
            log.info("client不存在,先走注册流程");
            imClient = new ImClient();
            imClient.setId(new Snowflake(1L, 1L).nextId());
            imClient.setFkAppid(imApplication.getId());
            imClient.setClientId(imTokenVerify.getClientId());
            imClientService.save(imClient);
        }

        // 生成token
        String generateToken = JwtUtil.generateToken(imTokenVerify.getClientId(), imTokenVerify.getAppKey(), secret, Duration.ofDays(99999));

        //  保存redis
//        redisTemplate.opsForValue().set("client:" + imApplication.getAppKey() + ":" + imTokenVerify.getClientId(), generateToken);

        JwtToken jwtToken = JwtToken.build(generateToken, secret, jwtProperties.getExpireSecond(), imClient.getClientId(), imTokenVerify.getAppKey());
        appLoginRedisService.cacheLoginInfo(jwtToken);

        TokenVo tokenVo = new TokenVo();
        tokenVo.setToken(generateToken);
        tokenVo.setWsAddr(wsInstance.selectOneHealthyInstance());
        tokenVo.setId(imClient.getId());
        tokenVo.setAttributes(imClient.getAttributes());
        return ApiResult.ok(tokenVo);
    }

}
