package cn.axzo.msg.center.inside.notices.service.impl;

import cn.axzo.msg.center.dal.TingyunInterfaceListDao;
import cn.axzo.msg.center.dal.mapper.TingyunInterfaceListMapper;
import cn.axzo.msg.center.domain.entity.TingyunInterfaceList;
import cn.axzo.msg.center.inside.notices.utils.Queries;
import cn.axzo.msg.center.notices.manager.api.dto.request.plat.TingyunInterfaceListRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.util.concurrent.Uninterruptibles;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.apache.commons.collections4.CollectionUtils;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static java.util.stream.Collectors.toSet;

/**
 * @author yanglin
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TingyunService {

    private final TingyunInterfaceListDao tingyunInterfaceListDao;
    private final TingyunInterfaceListMapper tingyunInterfaceListMapper;
    private final ExecutorService scheduler = Executors.newSingleThreadExecutor();
    private volatile boolean isRunning = false;
    private volatile boolean aborted = false;

    public String interfaceList(TingyunInterfaceListRequest request) {
        synchronized (this) {
            if (isRunning)
                return "前面一个操作正在执行中..";
            isRunning = true;
        }
        scheduler.execute(() -> {
            try {
                interfaceListImpl(request);
            } catch (Exception e) {
                log.error("执行失败", e);
            } finally {
                synchronized (this) {
                    isRunning = false;
                    aborted = false;
                }
            }
        });
        return "scheduled...";
    }

    public synchronized void abort() {
        aborted = true;
    }

    private void interfaceListImpl(TingyunInterfaceListRequest request) throws Exception {
        log.info("开始执行, request={}", request);
        Set<Long> applicationIds = request.getActions().stream()
                .map(TingyunInterfaceListRequest.ActionInfo::getApplicationId)
                .collect(toSet());
        tingyunInterfaceListMapper.delete(Queries.query(TingyunInterfaceList.class)
                .in(TingyunInterfaceList::getApplicationId, applicationIds));
        OkHttpClient httpClient = httpClient();
        DateTime startDate = new DateTime(request.determineStartDate());
        DateTime endDate = new DateTime(request.determineEndDate());
        outer:
        for (TingyunInterfaceListRequest.ActionInfo action : request.getActions()) {
            for (DateTime date = startDate;
                 date.isBefore(endDate) || date.isEqual(endDate);
                 date = date.plusDays(1)) {

                if (aborted) {
                    log.info("中断执行, request={}", request);
                    break outer;
                }

                FormBody formBody = new FormBody.Builder()
                        .add("timePeriod", "1440")
                        .add("endTime", date.toString("yyyy-MM-dd 00:00"))
                        .add("bizSystemId", request.getBizSystemId() + "")
                        .add("sortField", "response")
                        .add("sortDirection", "DESC")
                        .add("actionName", action.getActionName())
                        .add("applicationId", action.getApplicationId() + "")
                        .build();

                Request httpRequest = new Request.Builder()
                        .post(formBody)
                        .header("accept", "application/json, text/plain, */*")
                        .header("authorization", request.getAuth())
                        .url("https://wukong1.tingyun.com/server-api/webaction/list/interfaceList")
                        .build();

                String responseBody = httpClient.newCall(httpRequest).execute().body().string();
                JSONObject resp = JSON.parseObject(responseBody);
                if (resp.getIntValue("code") != 200)
                    throw new RuntimeException("请求失败: " + responseBody);
                List<TingyunInterfaceList> content = resp.getObject("data", InterfaceListData.class).getContent();
                if (CollectionUtils.isNotEmpty(content)) {
                    Date d = date.toDate();
                    content.forEach(c -> c.setDate(d));
                    tingyunInterfaceListDao.saveBatch(content);
                } else {
                    TingyunInterfaceList empty = TingyunInterfaceList.emptyResponse(
                            action.getApplicationId(), action.getActionName(), date.toDate());
                    tingyunInterfaceListMapper.insert(empty);
                }

                Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
            }
        }
        log.info("结束执行, request={}", request);
    }

    private OkHttpClient httpClient() {
        return new OkHttpClient.Builder()
                // 设置连接超时时间
                .connectTimeout(Duration.ofSeconds(30))
                // 设置读超时时间
                .readTimeout(Duration.ofSeconds(60))
                // 设置写超时时间
                .writeTimeout(Duration.ofSeconds(60))
                // 设置完整请求超时时间
                .callTimeout(Duration.ofSeconds(120))
                .build();
    }

    @Data
    public static class TingyunResponse<T> {
        private int code;
        private T date;
    }

    @Data
    public static class InterfaceListData {
        private int totalElements;
        private List<TingyunInterfaceList> content;
    }
}
