package com.nokia.domainb.capability.controller;

import com.alibaba.fastjson2.JSON;
import com.nokia.domainb.DomainBApplication;
import com.nokia.domainb.dto.RouteDTO;
import com.nokia.domainb.dto.SaAndVolteDTO;
import com.nokia.domainb.dto.SaDTO;
import com.nokia.common.http.R;
import com.nokia.domainb.dto.UserStateDTO;
import com.nokia.domainb.util.Utils;
import de.siegmar.fastcsv.reader.CsvReader;
import de.siegmar.fastcsv.reader.CsvRow;
import de.siegmar.fastcsv.writer.CsvWriter;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Set;

@Slf4j
@SpringBootTest(classes = DomainBApplication.class)
class DomainControllerTest {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    ThreadPoolTaskScheduler threadPoolTaskScheduler;

    /**
     * 路由查询并发测试
     */
    @Test
    void testRoute() {
        // 每个请求结果保存的路径
        String singlePath = "z:/route/single/";
        // 合并结果保存的路径
        String resultPath = "z:/route/";
        // 创建文件夹
        try {
            Files.createDirectories(Paths.get(singlePath));
            Files.createDirectories(Paths.get(resultPath));
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        resultPath = resultPath + "路由查询10个线程10000条数据测试结果.csv";
//        resultPath = resultPath + "路由查询10个线程1000条数据测试结果.csv";
//        resultPath = resultPath + "路由查询10个线程100条数据测试结果.csv";
        // 接口地址
        String url = "http://133.96.94.108:12091/domainB/api/route/";
        Set<String> phones = Utils.readPhones();
        for (String t : phones) {
            String[] a = t.split(",");
            String phoneNumber = a[0];
            RouteDTO dto = new RouteDTO("test", phoneNumber);
            threadPoolTaskScheduler.submit(new Task(restTemplate, phoneNumber, url, dto, singlePath));
        }
        // 等待所有任务执行结束
        while (threadPoolTaskScheduler.getActiveCount() > 0) {
        }
        mergeResult(phones, resultPath, singlePath);
    }

    /**
     * 5GSA查询并发测试
     */
    @Test
    void testSa() {
        // 每个请求结果保存的路径
        String singlePath = "z:/sa/single/";
        // 合并结果保存的路径
        String resultPath = "z:/sa/";
        // 创建文件夹
        try {
            Files.createDirectories(Paths.get(singlePath));
            Files.createDirectories(Paths.get(resultPath));
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        resultPath = resultPath + "5GSA查询10个线程10000条数据测试结果.csv";
//        resultPath = resultPath + "5GSA查询10个线程1000条数据测试结果.csv";
//        resultPath = resultPath + "5GSA查询10个线程100条数据测试结果.csv";
        // 接口地址
        String url = "http://133.96.94.108:12091/domainB/api/sa/";
        Set<String> phones = Utils.readPhones();
        for (String t : phones) {
            String[] a = t.split(",");
            String phoneNumber = a[0];
            SaDTO dto = new SaDTO("test", phoneNumber);
            threadPoolTaskScheduler.submit(new Task(restTemplate, phoneNumber, url, dto, singlePath));
        }
        // 等待所有任务执行结束
        while (threadPoolTaskScheduler.getActiveCount() > 0) {
        }
        mergeResult(phones, resultPath, singlePath);
    }

    /**
     * 功能查询并发测试
     */
    @Test
    void testSaAndVolte() {
        // 每个请求结果保存的路径
        String singlePath = "z:/saAndVolte/single/";
        // 合并结果保存的路径
        String resultPath = "z:/saAndVolte/";
        // 创建文件夹
        try {
            Files.createDirectories(Paths.get(singlePath));
            Files.createDirectories(Paths.get(resultPath));
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        resultPath = resultPath + "功能查询10个线程10000条数据测试结果.csv";
//        resultPath = resultPath + "功能查询10个线程1000条数据测试结果.csv";
//        resultPath = resultPath + "功能查询10个线程100条数据测试结果.csv";
        // 接口地址
        String url = "http://133.96.94.108:12091/domainB/api/product/saAndVolte/";
        Set<String> phones = Utils.readPhones();
        for (String t : phones) {
            String[] a = t.split(",");
            String phoneNumber = a[0];
            SaAndVolteDTO dto = new SaAndVolteDTO("test", phoneNumber);
            threadPoolTaskScheduler.submit(new Task(restTemplate, phoneNumber, url, dto, singlePath));
        }
        // 等待所有任务执行结束
        while (threadPoolTaskScheduler.getActiveCount() > 0) {
        }
        mergeResult(phones, resultPath, singlePath);
    }

    /**
     * 用户资料三户返回并发测试
     */
    @Test
    void testUserState() {
        // 每个请求结果保存的路径
        String singlePath = "z:/userState/single/";
        // 合并结果保存的路径
        String resultPath = "z:/userState/";
        // 创建文件夹
        try {
            Files.createDirectories(Paths.get(singlePath));
            Files.createDirectories(Paths.get(resultPath));
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        resultPath = resultPath + "用户资料三户返回10个线程7月1-24日移网质量投诉业务号码测试结果.csv";
        // 接口地址
        String url = "http://133.96.94.108:12091/domainB/api/threePart/userState/";
        Set<String> phones = Utils.readPhones();
        for (String t : phones) {
            String[] a = t.split(",");
            String phoneNumber = a[0];
            UserStateDTO dto = new UserStateDTO("test", phoneNumber);
            threadPoolTaskScheduler.submit(new Task(restTemplate, phoneNumber, url, dto, singlePath));
        }
        // 等待所有任务执行结束
        while (threadPoolTaskScheduler.getActiveCount() > 0) {
        }
        mergeResult(phones, resultPath, singlePath);
    }

    /**
     * 合并结果
     *
     * @param phones     手机列表
     * @param resultPath 合并结果保存路径
     * @param singlePath 单个结果保存路径
     */
    private void mergeResult(Set<String> phones, String resultPath, String singlePath) {
        OutputStreamWriter osw;
        try {
            osw = new OutputStreamWriter(Files.newOutputStream(Paths.get(resultPath)), "GBK");
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        CsvWriter csvWriter = CsvWriter.builder().build(osw);
        csvWriter.writeRow("入参", "时间", "调用时长", "结果");
        for (String tt : phones) {
            String[] a = tt.split(",");
            String phone = a[0];
            Path path = Paths.get(singlePath + phone + ".csv");
            try (CsvReader csvReader = CsvReader.builder().build(path, StandardCharsets.UTF_8)) {
                for (CsvRow row : csvReader) {
                    csvWriter.writeRow(row.getField(0), row.getField(1), row.getField(2),
                            row.getField(3));
                }
            } catch (IOException e) {
                log.error("{} -> {}", phone, e.getMessage(), e);
            }
        }
        try {
            csvWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @AllArgsConstructor
    class Task implements Runnable {
        private RestTemplate restTemplate;
        private String phoneNumber;
        private String url;
        private Object dto;
        private String singlePath;

        @Override
        public void run() {
            String filePath = singlePath + phoneNumber + ".csv";
            LocalDateTime startTime = LocalDateTime.now();
            long startTimestamp = System.currentTimeMillis();
            R r;
            try {
                r = restTemplate.postForObject(url, dto, R.class);
            } catch (Exception e) {
                long endTimestamp = System.currentTimeMillis();
                long cost = endTimestamp - startTimestamp;
                log.error("{} cost {} -> {}", phoneNumber, cost, e.getMessage(), e);
                try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(Paths.get(filePath)),
                        StandardCharsets.UTF_8);
                     CsvWriter csv = CsvWriter.builder().build(osw);) {
                    csv.writeRow(JSON.toJSONString(dto), startTime.toString(), String.valueOf(cost),
                            JSON.toJSONString(e.getMessage()));
                    return;
                } catch (IOException ioException) {
                    log.error("{} cost {} -> {}", phoneNumber, cost, ioException.getMessage(), ioException);
                    return;
                }
            }
            long endTimestamp = System.currentTimeMillis();
            long cost = endTimestamp - startTimestamp;
            try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(Paths.get(filePath)),
                    StandardCharsets.UTF_8);
                 CsvWriter csv = CsvWriter.builder().build(osw);) {
                csv.writeRow(JSON.toJSONString(dto), startTime.toString(), String.valueOf(cost), JSON.toJSONString(r));
            } catch (IOException e) {
                log.error("{} cost {} -> {}", phoneNumber, cost, e.getMessage(), e);
            }
        }
    }
}

