package com.sikey.wa04.business.application.service;

import cn.hutool.core.util.StrUtil;
import cn.ucloud.common.config.Config;
import cn.ucloud.common.credential.Credential;
import cn.ucloud.usms.client.USMSClient;
import cn.ucloud.usms.models.SendUSMSMessageRequest;
import cn.ucloud.usms.models.SendUSMSMessageResponse;
import com.sikey.wa04.business.domain.usecase.SMSCodeVerifier;
import com.sikey.wa04.business.infrastructure.configuration.UCloudConfig;
import com.sikey.wa04.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.List;
import java.util.Objects;

/**
 * UCloud
 */
@Slf4j
@Service
public class UcloudService extends BaseService {
    private static final String SMS_CODE_PREFIX = "sms.code.%s";
    private static final String SMS_CODE_LIMIT_PREFIX = "sms.limit.%s";

    private static final Duration SMS_CODE_EXPIRE = Duration.ofMinutes(3);
    private static final Duration SMS_CODE_LIMIT_EXPIRE = Duration.ofDays(1);

    private static final Long SMS_CODE_LIMIT_MAX = 10L;

    private static final String SMS_CODE_DEFAULT_VALUE = "0000";

    private final SMSCodeVerifier smsCodeVerifier;
    private final RedisOperations<String, String> operations;
    private final UCloudConfig ucloudConfig;

    @Autowired
    public UcloudService(SMSCodeVerifier smsCodeVerifier, RedisOperations<String, String> operations,
                         UCloudConfig ucloudConfig) {
        this.smsCodeVerifier = smsCodeVerifier;
        this.operations = operations;
        this.ucloudConfig = ucloudConfig;
    }

    /**
     * 检查手机号限制
     *
     * @param phone 手机号
     * @return 是否限制
     */
    private Boolean checkPhoneLimit(String phone, String areaCode) {
        String key = String.format(SMS_CODE_LIMIT_PREFIX, areaCode + phone);
        Long count = operations.opsForValue().increment(key);
        Objects.requireNonNull(count, "Failed to increment phone limit");

        // 如果是第一次设置，设置过期时间
        if (count.equals(1L)) {
            operations.expire(key, SMS_CODE_LIMIT_EXPIRE);
        }

        return count.compareTo(SMS_CODE_LIMIT_MAX) >= 0;
    }

    /**
     * 发送验证码
     *
     * @param phone    手机号
     * @param areaCode 区号
     */
    public void sendSMSCode(String phone, String areaCode) {
        log.info("Send SMS code {}", phone);

        if (checkPhoneLimit(phone, areaCode)) {
            throw new BusinessException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "短信每日发送次数超限");
        }
        final String randCode = smsCodeVerifier.generation();

        SendUSMSMessageRequest sendUSMSMessageRequest = new SendUSMSMessageRequest();
        sendUSMSMessageRequest.setSigContent(ucloudConfig.getSigContent());
        sendUSMSMessageRequest.setTemplateId(ucloudConfig.getTemplateId());
        sendUSMSMessageRequest.setPhoneNumbers(List.of(phone));
        sendUSMSMessageRequest.setTemplateParams(List.of(randCode));

        Config config = new Config();
        config.setProjectId(ucloudConfig.getProjectId());
        Credential credential = new Credential(ucloudConfig.getPublicKey(), ucloudConfig.getPrivateKey());
        try (USMSClient client = new USMSClient(config, credential)) {
            SendUSMSMessageResponse response = client.sendUSMSMessage(sendUSMSMessageRequest);
            if (response.getRetCode().equals(0)) {

                // 数据储存到 Redis
                redisStorageSMSCode(phone, areaCode, randCode);

                log.info("SMS code sent successfully {} & {}", phone, randCode);
            }
        } catch (Exception e) {
            log.error("Failed to send SMS code: {}", e.getMessage());
        }
    }

    /**
     * 数据储存到Redis
     *
     * @param phone 手机号
     * @param code  验证码
     */
    private void redisStorageSMSCode(String phone, String areaCode, String code) {
        String key = String.format(SMS_CODE_PREFIX, areaCode + phone);
        operations.opsForValue().set(key, code);
        operations.expire(key, SMS_CODE_EXPIRE);
    }

    /**
     * 验证
     *
     * @param phone    手机号
     * @param areaCode 区号
     * @param code     验证码
     */
    public boolean validation(String phone, String areaCode, String code) {
        // 如果输入的值是默认值，直接返回 true
        if (!ucloudConfig.isRelease() && SMS_CODE_DEFAULT_VALUE.equals(code)) {
            log.warn("SMS code is default value, skip verification");
            return true;
        }

        // 过滤掉区号里的加号
        areaCode = StrUtil.replace(areaCode, "+", "");
        String key = String.format(SMS_CODE_PREFIX, areaCode + phone);
        String storedCode = operations.opsForValue().get(key);
        if (!code.equals(storedCode)) {
            return false;
        }

        log.info("SMS code validation success areaCode={}", areaCode);
        // operations.delete(key);
        return true;
    }
}
