package com.yinlihupo.enlish.service.service.login;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.RandomUtil;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teautil.models.RuntimeOptions;
import com.yinlihupo.enlish.service.constant.UserRedisConstants;
import com.yinlihupo.enlish.service.domain.dataobject.UserDO;
import com.yinlihupo.enlish.service.domain.mapper.UserDOMapper;
import com.yinlihupo.enlish.service.service.LoginService;
import com.yinlihupo.framework.common.util.JsonUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class LoginServiceImpl implements LoginService {

    @Resource
    private UserDOMapper userDOMapper;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private Client client;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void login(String phone, String name, String reqPassword, String reqCode, String invitationCode) {
        UserDO userDO = userDOMapper.selectByPhone(phone);
        log.info("userDO:{}", userDO);

        String code = JsonUtils.toJsonString(redisTemplate.opsForValue().get(UserRedisConstants.buildUserLoginCode(phone)));
        if (userDO == null) {
            if (code == null || !code.equals(reqCode)) {
                throw new RuntimeException("验证码错误");
            }

            Object invitationObj = redisTemplate.opsForValue().get(UserRedisConstants.buildUserInvitationCode(invitationCode));
            if (invitationObj == null) {
                throw new RuntimeException("邀请码错误");
            }
            int invitationLimit = Integer.parseInt(JsonUtils.toJsonString(invitationObj));
            if (invitationLimit <= 0) {
                throw new RuntimeException("邀请码已使用完毕");
            }
            redisTemplate.opsForValue().set(UserRedisConstants.buildUserInvitationCode(invitationCode), invitationLimit - 1);

            userDO = UserDO.builder()
                    .phone(phone)
                    .name(name)
                    .password(passwordEncoder.encode(reqPassword))
                    .build();
            userDOMapper.insert(userDO);
            StpUtil.login(userDO.getId());
            return;
        }

        if (code != null && code.equals(reqCode)) {
            StpUtil.login(userDO.getId());
            return;
        }

        if (reqPassword != null && passwordEncoder.matches(reqPassword, userDO.getPassword())) {
            StpUtil.login(userDO.getId());
            return;
        }

        throw new RuntimeException("登录错误");
    }

    @Override
    public void sendVerificationCode(String phone) {
        String code = RandomUtil.randomNumbers(6);
        String key = UserRedisConstants.buildUserLoginCode(phone);
        redisTemplate.opsForValue().set(key, code);
        redisTemplate.expire(key, 5, TimeUnit.MINUTES);
        String signName = "短信测试";
        String templateCode = "SMS_154950909";
        String templateParam = String.format("{\"code\":\"%s\"}", code);
        try {
            sendMessage(phone, signName, templateCode, templateParam);
        } catch (Exception e) {
            log.error("==> 短信发送失败, phone: {}, signName: {}, templateCode: {}, templateParam: {}", phone, signName, templateCode, templateParam);
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送短信
     */
    public void sendMessage(String signName, String templateCode, String phone, String templateParam) throws Exception {
        SendSmsRequest sendSmsRequest = new SendSmsRequest()
                .setSignName(signName)
                .setTemplateCode(templateCode)
                .setPhoneNumbers(phone)
                .setTemplateParam(templateParam);
        RuntimeOptions runtime = new RuntimeOptions();


        log.info("==> 开始短信发送, phone: {}, signName: {}, templateCode: {}, templateParam: {}", phone, signName, templateCode, templateParam);

        // 发送短信
        SendSmsResponse response = client.sendSmsWithOptions(sendSmsRequest, runtime);

        log.info("==> 短信发送成功, response: {}", JsonUtils.toJsonString(response));

    }
}
