package com.izouma.nineth.service.sms;

import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.izouma.nineth.config.AliyunProperties;
import com.izouma.nineth.config.Constants;
import com.izouma.nineth.domain.SmsRecord;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.repo.SmsRecordRepo;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.HashMap;

@Service
@Slf4j
public class AliSmsService implements SmsService {

    @Autowired
    private AliyunProperties aliyunProperties;

    @Autowired
    private SmsRecordRepo smsRecordRepo;

    private IAcsClient client;

    @PostConstruct
    public void init(){
        if (!"身份验证".equals(aliyunProperties.getSmsSign())) {
            //第三方的
            aliyunProperties.setSmsAccessKeyId(aliyunProperties.getAccessKeyId());
            aliyunProperties.setSmsAccessKeySecret(aliyunProperties.getAccessKeySecret());
        }

        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou",
                aliyunProperties.getSmsAccessKeyId(), aliyunProperties.getSmsAccessKeySecret());
        client = new DefaultAcsClient(profile);
    }

    @Override
    public String sendVerify(String phone) {

        smsRecordRepo.findLastByPhoneAndExpiresAtAfterAndExpiredFalse(phone, LocalDateTime.now()).ifPresent(record -> {
            if (record.getCreatedAt().plusMinutes(1L).isAfter(LocalDateTime.now())) {
                long sec = record.getCreatedAt().plusMinutes(1L).toInstant(ZoneOffset.UTC)
                        .getEpochSecond() - LocalDateTime.now().toInstant(ZoneOffset.UTC).getEpochSecond() + 1;
                throw new BusinessException("请" + sec + "秒后再试");
            }
        });

        String code = RandomStringUtils.randomNumeric(4);

        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");
        request.putQueryParameter("PhoneNumbers", phone);
        request.putQueryParameter("SignName", aliyunProperties.getSmsSign());
        request.putQueryParameter("TemplateCode", aliyunProperties.getSmsCode());
        if ("身份验证".equals(aliyunProperties.getSmsSign())) {
            request.putQueryParameter("TemplateParam", "{\"code\":\"" + code + "\",\"product\":\"用户\"}");
        } else {
            request.putQueryParameter("TemplateParam", "{\"code\":\"" + code + "\"}");
        }
        CommonResponse response = null;
        try {
            response = client.getCommonResponse(request);
            if (response.getHttpStatus() != 200) {
                throw new BusinessException("发送失败，请稍后再试", response.getHttpStatus() + "," + response.getData());
            }
            log.info("send sms response {}", response.getData());
            JSONObject jsonObject = new JSONObject(response.getData());
            if (!"ok".equalsIgnoreCase(jsonObject.getString("Code"))) {
                throw new BusinessException("发送失败，请稍后再试", jsonObject.getString("Message"));
            }
            smsRecordRepo.expire(phone);
            String sessionId = RandomStringUtils.randomAlphabetic(10);
            smsRecordRepo.save(SmsRecord.builder()
                    .sessionId(sessionId)
                    .phone(phone)
                    .code(code)
                    .expiresAt(LocalDateTime.now().plusMinutes(5))
                    .expired(false)
                    .build());
            return sessionId;
        } catch (ClientException | JSONException e) {
            log.error("短信发送失败:" + phone, e);
            throw new BusinessException("发送失败，请稍后再试", e.getMessage());
        }
    }

    @Override
    public String verify(String phone, String code) {
        SmsRecord smsRecord = smsRecordRepo.findLastByPhoneAndExpiresAtAfterAndExpiredFalse(phone, LocalDateTime.now())
                .orElseThrow(new BusinessException("短信验证码错误"));
        if (!smsRecord.getCode().equalsIgnoreCase(code)) {
            throw new BusinessException("短信验证码错误");
        }
        smsRecord.setExpired(true);
        smsRecordRepo.save(smsRecord);

        return Jwts.builder()
                .setClaims(new HashMap<>())
                .setSubject(phone)
                .setIssuedAt(new Date())
                .setExpiration(new Date(new Date().getTime() + 10 * 60 * 1000)) //10min
                .signWith(SignatureAlgorithm.HS512, Constants.SMS_TOKEN_SECRET)
                .compact();
    }

}
