package com.huiju.estateagents.common;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.huiju.estateagents.config.SMSProperties;
import com.huiju.estateagents.entity.SysSmsSetting;
import com.huiju.estateagents.mapper.SysSmsSettingMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Configuration
@EnableConfigurationProperties(SMSProperties.class)
public class SMSUtils {
    // 短信服务配置
    SMSProperties smsProperties;

    Hashtable<String, Phone> allPhones;

    @Autowired
    SysSmsSettingMapper sysSmsSettingMapper;

    @Autowired
    public SMSUtils(SMSProperties properties) {
        smsProperties = properties;
        allPhones = new Hashtable<>();
    }

    /**
     * 发送验证码到 tel
     * @param tel
     * @return
     */
    public boolean sendCaptcha(String tel) {
        Phone phone = allPhones.get(tel);
        if (null == phone) {
            phone = new Phone();
            phone.setTel(tel);
        }

        phone.setCaptcha(genCaptcha(smsProperties.getCaptcha().getSize()));
        phone.setExpire(LocalDateTime.now().plusSeconds(smsProperties.getCaptcha().getExpire()));
        allPhones.put(tel, phone);

        log.info("发送手机 {} 验证码 {}", tel, phone.getCaptcha());

        String[] params = { phone.getCaptcha(), smsProperties.getCaptcha().getSign() };
        return sendMessage(smsProperties.getCaptcha().getCode(), tel, params);
    }

    /**
     * 校验验证码
     * @param tel
     * @param smsCaptcha
     * @return
     */
    public boolean checkCaptcha(String tel, String smsCaptcha) {
        Phone phone = allPhones.get(tel);
        if (null == phone) {
            log.error("手机号 {} 的验证码未找到", tel);
            return false;
        }

        if (null == smsCaptcha || !smsCaptcha.equals(phone.getCaptcha())) {
            log.error("手机号 {} 校验验证码出错, 正确: {}, 错误: {}", tel, phone.getCaptcha(), smsCaptcha);
            return false;
        }

        LocalDateTime now = LocalDateTime.now();
        if (now.isAfter(phone.getExpire())) {
            log.error("手机号 {} 的验证码已过期", tel);
            return false;
        }

        // 如果验证成功, 则从缓存中删除
        allPhones.remove(tel);
        return true;
    }

    public boolean sendVisitor(String tel, String name) {
        log.info("发送手机 {} 客户名称 {}", tel, name);

        String[] params = { name };
        return sendMessage(smsProperties.getVisitor().getCode(), tel, params);
    }

    private String genCaptcha(int length) {
        List<String> nums = new ArrayList<>();
        for (int i = 0; i < length; i ++) {
            int rand = (new Random()).nextInt(10);
            nums.add(String.valueOf(rand));
        }
        return String.join("", nums);
    }

    public boolean sendMessage(String code, String tel, String[] params) {
        // 发送内容
        SMSProperties.Template message = new SMSProperties.Template();
        message.setCode(code);
        message.setTel(tel);
        message.setParams(params);

        // 构造 request
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType(smsProperties.getContentType()));
//        String body = JSONObject.toJSONString(message);
        HttpMethod method = HttpMethod.resolve(smsProperties.getMethod());
        HttpEntity requestEntity = new HttpEntity(message, headers);

        RestTemplate template = new RestTemplate();
        HttpEntity<String> response = template.exchange(
                smsProperties.getUrl(),
                method,
                requestEntity,
                String.class,
                new Object()
        );

        if (((ResponseEntity<String>) response).getStatusCodeValue() != HttpStatus.OK.value()) {
            log.error("请求发送短信失败: {}", response.toString());
            return false;
        }

        return true;
    }

    public void sendMessage(String tel, List<String> params, String type) throws Exception {
        if (StringUtils.isEmpty(tel) || StringUtils.isEmpty(type)) {
            throw new Exception("短信发送失败: 没有手机号或者短信模板");
        }

        QueryWrapper<SysSmsSetting> query = new QueryWrapper<>();
        query.eq("sms_type", type);
        query.eq("status", CommConstant.STATUS_NORMAL);
        query.last("limit 1");

        SysSmsSetting smsSetting = sysSmsSettingMapper.selectOne(query);
        if (null == smsSetting) {
            throw new Exception("没有设置有效的【" + type + "】短信模板");
        }

        params.add("橙蕉"); // 短信签名
        String[] paramArr = new String[params.size()];
        params.toArray(paramArr);

        boolean success = sendMessage(smsSetting.getTplCode(), tel, paramArr);
        if (!success) {
            throw new Exception("短信发送失败");
        }
    }

    @Data
    public static class Phone {
        String tel;
        String captcha;
        LocalDateTime expire;
    }
}
