package com.nokia.sms.service;

import com.alibaba.fastjson2.JSON;
import com.nokia.common.http.R;
import com.nokia.sms.dao.SmsDao;
import com.nokia.sms.pojo.Sms;
import com.nokia.sms.pojo.SmsReport;
import com.nokia.sms.sgip.message.SendResult;
import com.nokia.sms.sgip.mt.client.MTClient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;

@Slf4j
@Service
@Data
@ConfigurationProperties("sms")
public class SgipSmsService {
    static final LinkedBlockingQueue<Sms> QUEUE = new LinkedBlockingQueue<>();
    private final SmsDao smsDao;
    private final MTClient mtClient;

    /**
     * 最大重试次数
     */
    private Integer maxRetry;

    public SgipSmsService(SmsDao smsDao, MTClient mtClient) {
        this.smsDao = smsDao;
        this.mtClient = mtClient;
    }

    /**
     * 短信放入队列
     *
     * @param sms 短信
     * @return {@link R}
     */
    public R offer(Sms sms) {
        if (!QUEUE.offer(sms)) {
            log.error("入队失败");
            return R.error();
        }
        return R.ok();
    }

    public void sendMessage(Sms sms) {
        List<SmsReport> smsReportList = new ArrayList<>();
        LinkedHashMap<String, String> sendResultMap = new LinkedHashMap<>();
        try {
            log.debug("准备发送短信: {}", JSON.toJSONString(sms));
            String id = UUID.randomUUID().toString();
            sms.setId(id);
            sms.setSendTime(new Date());
            for (String phoneNumber : sms.getPhoneNumbers()) {
                // 发送短信
                SendResult[] results = mtClient.sendMessage(phoneNumber, sms.getContent(), sms.getScheduleTime());
                String resultString = Arrays.toString(results);
                log.debug("{}短信已成功发送, 发送结果: {}", phoneNumber, resultString);
                sendResultMap.put(phoneNumber, resultString);
                sms.setResult(JSON.toJSONString(sendResultMap));
                for (SendResult result : results) {
                    String flowId = Arrays.stream(result.getFlowId())
                            .mapToObj(Integer::toString).collect(Collectors.joining("-"));
                    SmsReport smsReport = new SmsReport();
                    smsReport.setId(id);
                    smsReport.setPhone(phoneNumber);
                    smsReport.setSendTime(new Date());
                    smsReport.setFlowId(flowId);
                    smsReportList.add(smsReport);
                }
            }
//            if (ThreadLocalRandom.current().nextBoolean()) {
//                throw new RuntimeException("异常测试");
//            }
            sms.setStatus("已发送到短信网关");
            log.info("短信发送成功: {}", JSON.toJSONString(sms));
        } catch (Exception e) {
            sms.setStatus("发送到短信网关失败");
            log.error("短信发送失败, 短信: {}, 错误信息: {}", sms, e.getMessage(), e);
            // 重试次数小于最大重试次数进行重试
            if (sms.getCount().getAndIncrement() < maxRetry) {
                retry(sms);
            }
        } finally {
            smsDao.insert(sms);
            smsDao.insertBatchSmsReport(smsReportList);
        }
    }

    /**
     * 消费队列发送短信
     */
    @PostConstruct
    public void consumerSendQueue() {
        CompletableFuture.runAsync(() -> {
            while (true) {
                try {
                    Sms sms = QUEUE.take();
                    sendMessage(sms);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.error(e.getMessage(), e);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        });
    }

    /**
     * 消费短信报告队列更新数据库
     */
    @PostConstruct
    public void consumerReportQueue() {
        CompletableFuture.runAsync(() -> {
            while (true) {
                try {
                    SmsReport smsReport = SmsReport.take();
                    smsDao.updateSmsReport(smsReport);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.error(e.getMessage(), e);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        });
    }

    /**
     * 重试
     *
     * @param sms 短信
     */
    void retry(Sms sms) {
//        Instant startTime = Instant.now().plusSeconds(retryDelay);
//        scheduler.schedule(() -> sendMessage(sms), startTime);
        if (QUEUE.offer(sms)) {
            log.info("重新入队: {}", JSON.toJSONString(sms));
        } else {
            log.error("重新入队失败: {}", JSON.toJSONString(sms));
        }
    }
}
