package com.wecloud.im.biz.module.message.service.impl;

import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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.biz.core.balance.WsInstance;
import com.wecloud.im.biz.module.message.controller.param.ImTokenVerify;
import com.wecloud.im.biz.module.message.controller.vo.TokenVo;
import com.wecloud.im.biz.module.message.entity.ImApplication;
import com.wecloud.im.biz.module.message.entity.ImClient;
import com.wecloud.im.biz.module.message.entity.ImClientDevice;
import com.wecloud.im.biz.module.message.service.ImApplicationService;
import com.wecloud.im.biz.module.message.service.ImClientDeviceService;
import com.wecloud.im.biz.module.message.service.ImClientLoginService;
import com.wecloud.im.biz.module.message.service.ImClientService;
import com.wecloud.im.core.common.api.ApiCode;
import com.wecloud.im.core.common.api.ApiResult;
import com.wecloud.im.core.util.SnowflakeUtil;
import com.wecloud.im.security.cache.AppLoginRedisService;
import com.wecloud.im.security.jwt.JwtToken;
import com.wecloud.im.security.properties.JwtProperties;
import com.wecloud.im.security.util.JwtUtil;
import com.wecloud.im.security.util.SecurityUtils;

@Service
@Slf4j
public class ImClientLoginServiceImpl implements ImClientLoginService {

    private static JwtProperties jwtProperties;
    @Autowired
    private ImApplicationService imApplicationService;

    @Autowired
    private ImClientDeviceService imClientDeviceService;

    @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.getCacheAppByAppKey(imTokenVerify.getAppKey());

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

        if (imTokenVerify.getPlatform() == null) {
            log.error("platform is null , clientId is: {}", imTokenVerify.getClientId());
            return ApiResult.result(ApiCode.FAIL, null);
        }

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

        // 验证签名
        if (!mySign.equals(imTokenVerify.getSign())) {
            log.error("sign不一致,mySign:{},verify sign:{}", mySign, imTokenVerify.getSign());
            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(SnowflakeUtil.getId());
            imClient.setFkAppid(imApplication.getId());
            imClient.setClientId(imTokenVerify.getClientId());
            imClientService.save(imClient);
        }

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

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

        JwtToken jwtToken = JwtToken.build(generateToken, secret, jwtProperties.getExpireSecond(), imClient.getId(),
                imClient.getClientId(), imApplication.getId(), imTokenVerify.getAppKey(), imTokenVerify.getPlatform());
        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);
    }

    @Override
    public ApiResult<TokenVo> getToken(String clientId, Integer deviceType) throws NacosException {
        Long appId = SecurityUtils.getCurrentAppId();
        String appKey = SecurityUtils.getCurrentAppKey();
        ImApplication imApplication = imApplicationService.getCacheAppByAppKey(appKey);
        String appSecret = imApplication.getAppSecret();
        // 判断客户端是否存在，不存在则创建
        ImClient client = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                .eq(ImClient::getFkAppid, appId)
                .eq(ImClient::getClientId, clientId));

        if (client == null) {
            client = new ImClient();
            client.setId(SnowflakeUtil.getId());
            client.setFkAppid(appId);
            client.setClientId(clientId + "");
            imClientService.save(client);
        }
        // 判断客户端绑定的设备是否存在，不存在则创建
        ImClientDevice clientDevice = imClientDeviceService.getOneByAppIdAndClientIdAndType(appId,
                client.getId(), deviceType);

        if (clientDevice == null) {
            ImClientDevice imClientDevice = new ImClientDevice();
            imClientDevice.setId(SnowflakeUtil.getId());
            imClientDevice.setFkAppid(appId);
            imClientDevice.setFkClientId(client.getId());
            imClientDevice.setValid(1);
            imClientDevice.setDeviceType(deviceType);
            imClientDevice.setCreateTime(new Date());
            imClientDevice.setUpdateTime(new Date());
            imClientDeviceService.save(imClientDevice);
        }


        // 生成token
        String generateToken = JwtUtil.generateToken(clientId + "", appKey, appSecret, Duration.ofDays(99999),
                deviceType);
        JwtToken jwtToken = JwtToken.build(generateToken, appSecret, jwtProperties.getExpireSecond(),
                client.getId(), clientId + "",
                appId, appKey, deviceType);
        appLoginRedisService.cacheLoginInfo(jwtToken);

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