package com.nokia.tsl_data.service;

import com.nokia.tsl_data.dao.*;
import com.nokia.tsl_data.properties.TslDataProperties;
import com.nokia.tsl_data.util.CodecUtil;
import com.nokia.tsl_data.util.TextUtil;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 从能力商店订阅的表入库
 */
@Slf4j
@Service
public class DataWarehouseService {

    @Autowired
    private TslDataDao tslDataDao;
    @Autowired
    private MobileComplaintMapper mobileComplaintMapper;
    @Autowired
    private HighQualityCountMapper highQualityCountMapper;
    @Autowired
    private HighQualityListDayMapper highQualityListDayMapper;
    @Autowired
    private ComplaintDetailsFixYwdDayMapper complaintDetailsFixYwdDayMapper;
    @Autowired
    private CemMobileExperienceListMapper cemMobileExperienceListMapper;
    @Autowired
    private ManagementDetailMapper managementDetailMapper;
    @Autowired
    private SysDataDictionaryRepository sysDataDictionaryRepository;
    @Autowired
    private TslDataProperties tslDataProperties;

    /**
     * 入库前检查数据源是否具备
     */
    public String checkSource(String day) {
        StringBuffer stringBuffer = new StringBuffer();
        // 注意，只有文件已存在时才能 checkMD5， 否则读取MD5文件时必出异常
        // 河北_CEM移网质量投诉明细
        File mobileComplaintDayFile = getMobileComplaintDayFile(day);
        if (!mobileComplaintDayFile.exists()) {
            stringBuffer.append("河北_CEM移网质量投诉明细_HE_D_MOBILE_COMP表账期 ").append(day).append(" 数据未到达");
        } else if (!checkMD5(mobileComplaintDayFile)) {
            stringBuffer.append("河北_CEM移网质量投诉明细_HE_D_MOBILE_COMP表账期 ").append(day).append(" MD5验证未通过");
        }
        // 河北_CEM高品质2日明细
        File highQualityListDayFile = getHighQualityListDayFile(day);
        if (!highQualityListDayFile.exists()) {
            stringBuffer.append("河北_CEM高品质2日明细_HE_D_HIGH_QUALITY_LIST表账期 ").append(day).append(" 数据未到达");
        } else if (!checkMD5(highQualityListDayFile)) {
            stringBuffer.append("河北_CEM高品质2日明细_HE_D_HIGH_QUALITY_LIST表账期 ").append(day).append(" MD5验证未通过");
        }
        // 河北_CEM高品质2日统计
        File highQualityCountDayFile = getHighQualityCountDayFile(day);
        if (!highQualityCountDayFile.exists()) {
            stringBuffer.append("河北_CEM高品质2日统计_HE_D_HIGH_QUALITY_COUNT表账期 ").append(day).append(" 数据未到达");
        } else if (!checkMD5(highQualityCountDayFile)) {
            stringBuffer.append("河北_CEM高品质2日统计_HE_D_HIGH_QUALITY_COUNT表账期 ").append(day).append(" MD5验证未通过");
        }
        // 河北客户体验管理智能定责投诉明细月累计接口日
        File complaintDetailsFixYwdDayFile = getComplaintDetailsFixYwdDayFile(day);
        if (!complaintDetailsFixYwdDayFile.exists()) {
            stringBuffer.append("河北客户体验管理智能定责投诉明细月累计接口日 表账期 ").append(day).append(" 数据未到达");
        } else if (!checkMD5(complaintDetailsFixYwdDayFile)) {
            stringBuffer.append("河北客户体验管理智能定责投诉明细月累计接口日 表账期 ").append(day).append(" MD5验证未通过");
        }
        // 河北客户体验管理系统移网网络体验明细日信息
        File cemMobileExperienceListFile = getCemMobileExperienceListFile(day);
        if (!cemMobileExperienceListFile.exists()) {
            stringBuffer.append("河北客户体验管理系统移网网络体验明细日信息 表账期 ").append(day).append(" 数据未到达");
        } else if (!checkMD5(cemMobileExperienceListFile)) {
            stringBuffer.append("河北客户体验管理系统移网网络体验明细日信息 表账期 ").append(day).append(" MD5验证未通过");
        }
        return stringBuffer.toString();
    }

    /**
     * 入库全部文件的任务
     */
    public void warehouse(String day) {
        int count;
        if ((count = highQualityCountMapper.countForDay(day)) == 0) {
            warehouseHighQualityCountDay(day);
        } else {
            log.warn("HighQualityCount 账期 {} 已存在 {} 条数据，已跳过...", day, count);
        }
        if ((count = highQualityListDayMapper.countForDay(day)) == 0) {
            warehouseHighQualityListDay(day);
        } else {
            log.warn("HighQualityList 账期 {} 已存在 {} 条数据，已跳过...", day, count);
        }
        if ((count = mobileComplaintMapper.countForDay(day)) == 0) {
            warehouseMobileComplaintDay(day);
        } else {
            log.warn("MobileComplaint 账期 {} 已存在 {} 条数据，已跳过...", day, count);
        }
        if ((count = complaintDetailsFixYwdDayMapper.countForDay(day)) == 0) {
            warehouseComplaintDetailsFixYwdDay(day);
        } else {
            log.warn("complaintDetailsFixYwdDay 账期 {} 已存在 {} 条数据，已跳过...", day, count);
        }
        if ((count = cemMobileExperienceListMapper.countForDay(day)) == 0) {
            warehouseCemMobileExperienceList(day);
        } else {
            log.warn("CemMobileExperienceList 账期 {} 已存在 {} 条数据，已跳过...", day, count);
        }
    }

    /**
     * 删除 河北_CEM移网质量投诉明细 数据
     */
    public int deleteMobileComplaintDay(String day) {
        return mobileComplaintMapper.deleteMobileCompForDay(day);
    }

    /**
     * 删除 河北_CEM高品质2日统计 数据
     */
    public int deleteHighQualityCountDay(String day) {
        return highQualityCountMapper.deleteHighQualityCountForDay(day);
    }

    /**
     * 删除 河北_CEM高质量2日明细 数据
     */
    public int deleteHighQualityListDay(String day) {
        return highQualityListDayMapper.deleteHighQualityListForDay(day);
    }

    /**
     * 删除 河北客户体验管理智能定责投诉明细月累计接口日
     */
    public int deleteComplaintDetailsFixYwdDay(String day) {
        return tslDataDao.deleteComplaintDetailsFixYwdDay(day);
    }

    /**
     * 删除 河北客户体验管理系统移网网络体验明细日信息
     */
    public int deleteCemMobileExperienceList(String day) {
        return tslDataDao.deleteCemMobileExperienceList(day);
    }

    /**
     * 入库 河北高质量2日明细数据
     */
    public void warehouseHighQualityListDay(String day) {
        // 1. 检查是否已存在数据
        int countForDay = highQualityListDayMapper.countForDay(day);
        if (countForDay != 0) {
            throw new RuntimeException(
                String.format("HighQualityListDay 帐期 %s 已存在 %s 条数据", day, countForDay));
        }
        // 2. 入库新数据
        warehouseHighQualityListDay(getHighQualityListDayFile(day));
    }

    /**
     * 入库 河北_CEM移网质量投诉明细
     */
    public void warehouseMobileComplaintDay(String day) {
        // 1. 检查是否已存在数据
        int countForDay = mobileComplaintMapper.countForDay(day);
        if (countForDay != 0) {
            throw new RuntimeException(
                String.format("MobileComplaintDay 帐期 %s 已存在 %s 条数据", day, countForDay));
        }
        // 2. 入库新数据
        warehouseMobileComplaintDay(getMobileComplaintDayFile(day));
    }

    /**
     * 入库 河北_CEM高品质2日统计
     */
    public void warehouseHighQualityCountDay(String day) {
        // 1. 检查是否已存在数据
        int countForDay = highQualityCountMapper.countForDay(day);
        if (countForDay != 0) {
            throw new RuntimeException(
                String.format("HighQualityCountDay 帐期 %s 已存在 %s 条数据", day, countForDay));
        }
        // 2. 入库新数据
        warehouseHighQualityCountDay(getHighQualityCountDayFile(day));
    }

    /**
     * 入库 河北客户体验管理智能定责投诉明细月累计接口日 数据
     */
    public void warehouseComplaintDetailsFixYwdDay(String day) {
        // 1. 检查是否已存在数据
        int countForDay = complaintDetailsFixYwdDayMapper.countForDay(day);
        if (countForDay != 0) {
            throw new RuntimeException(
                String.format("ComplaintDetailsFixYwdDay 帐期 %s 已存在 %s 条数据", day, countForDay));
        }
        // 2. 入库新数据
        warehouseComplaintDetailsFixYwdDay(getComplaintDetailsFixYwdDayFile(day));
    }

    /**
     * 入库 河北客户体验管理系统移网网络体验明细日信息
     */
    public void warehouseCemMobileExperienceList(String day) {
        // 1. 检查是否已存在数据
        int countForDay = cemMobileExperienceListMapper.countForDay(day);
        if (countForDay != 0) {
            throw new RuntimeException(
                String.format("CemMobileExperienceList 帐期 %s 已存在 %s 条数据", day, countForDay));
        }
        // 2. 入库新数据
        warehouseCemMobileExperienceList(getCemMobileExperienceListFile(day));
    }

    private void warehouseHighQualityListDay(File file) {
        // 读取文件
        try (Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
            // SOH作为分割符
            char delimiter = 1;
            CSVParser parser = CSVFormat.DEFAULT.builder()
                    .setRecordSeparator("\n")
                    .setQuote(null)
                    .setDelimiter(delimiter)
                    .setSkipHeaderRecord(false)
                    .build().parse(reader);
            List<CSVRecord> records = parser.getRecords();
            List<Object[]> list = new ArrayList<>();
            // 查找全部需要筛选的类型
            Set<String> allServTypeNames = sysDataDictionaryRepository.findAllServTypeNames();
            for (CSVRecord record : records) {
                // 按照serv_type_name进行筛选
                if (allServTypeNames.contains(record.get(9))) {
                    Object[] ps = new Object[tslDataProperties.getFiledNumOfHighQualityListDay().intValue()];
                    list.add(ps);
                    for (int i = 0; i < ps.length; i++) {
                        ps[i] = record.get(i);
                    }
                }
            }
            tslDataDao.batchInsertHighQualityListDay(list);
            log.debug("河北_CEM高质量2日明细 数据入库成功...");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("河北_CEM高质量2日明细 数据入库失败..." + e.getMessage());
        }
    }

    private void warehouseMobileComplaintDay(File file) {
        try (Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
            // SOH作为分割符
            char delimiter = 1;
            CSVParser parser = CSVFormat.DEFAULT.builder()
                    .setRecordSeparator("\n")
                    .setQuote(null)
                    .setDelimiter(delimiter)
                    .setSkipHeaderRecord(false)
                    .build().parse(reader);
            List<CSVRecord> records = parser.getRecords();
            List<Object[]> list = new ArrayList<>();
            for (CSVRecord record : records) {
                Object[] ps = new Object[tslDataProperties.getFiledNumOfMobileComplaintDay().intValue()];
                list.add(ps);
                for (int i = 0; i < ps.length; i++) {
                    ps[i] = record.get(i);
                }
            }
            tslDataDao.batchInsertMobileComplaintDay(list);
            log.debug("河北_CEM移网质量投诉明细 数据入库成功...");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("河北_CEM移网质量投诉明细 数据入库失败..." + e.getMessage());
        }
    }

    private void warehouseHighQualityCountDay(File file) {
        try (Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
            // SOH作为分割符
            char delimiter = 1;
            CSVParser parser = CSVFormat.DEFAULT.builder()
                    .setRecordSeparator("\n")
                    .setQuote(null)
                    .setDelimiter(delimiter)
                    .setSkipHeaderRecord(false)
                    .build().parse(reader);
            List<CSVRecord> records = parser.getRecords();
            List<Object[]> list = new ArrayList<>();
            for (CSVRecord record : records) {
                Object[] ps = new Object[tslDataProperties.getFiledNumOfHighQualityCountDay().intValue()];
                list.add(ps);
                for (int i = 0; i < ps.length; i++) {
                    ps[i] = record.get(i);
                }
            }
            tslDataDao.batchInsertHighQualityCountDay(list);
            log.debug("河北_CEM高品质2日统计 数据入库成功...");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("河北_CEM高品质2日统计数据入库失败..." + e.getMessage());
        }
    }

    // 河北客户体验管理智能定责投诉明细月累计接口日
    private void warehouseComplaintDetailsFixYwdDay(File file) {
        try (Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
            // SOH作为分割符
            char delimiter = 1;
            CSVParser parser = CSVFormat.DEFAULT.builder()
                    .setRecordSeparator("\n")
                    .setQuote(null)
                    .setDelimiter(delimiter)
                    .setSkipHeaderRecord(false)
                    .build().parse(reader);
            List<CSVRecord> records = parser.getRecords();
            List<Object[]> list = new ArrayList<>();
            for (CSVRecord record : records) {
                Object[] ps = new Object[tslDataProperties.getFiledNumOfComplaintDetailsFixYwdDay().intValue()];
                list.add(ps);
                for (int i = 0; i < ps.length; i++) {
                    ps[i] = record.get(i);
                }
            }
            tslDataDao.batchInsertComplaintDetailsFixYwdDay(list);
            log.debug("河北客户体验管理智能定责投诉明细月累计接口日 数据入库成功...");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("河北客户体验管理智能定责投诉明细月累计接口日..." + e.getMessage());
        }
    }

    // 河北客户体验管理系统移网网络体验明细日信息
    private void warehouseCemMobileExperienceList(File file) {
        try (Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
            // SOH作为分割符
            char delimiter = 1;
            CSVParser parser = CSVFormat.DEFAULT.builder()
                    .setRecordSeparator("\n")
                    .setQuote(null)
                    .setDelimiter(delimiter)
                    .setSkipHeaderRecord(false)
                    .build().parse(reader);
            List<CSVRecord> records = parser.getRecords();
            List<Object[]> list = new ArrayList<>();
            for (CSVRecord record : records) {
                Object[] ps = new Object[tslDataProperties.getFiledNumOfCemMobileExperienceList().intValue()];
                list.add(ps);
                for (int i = 0; i < ps.length; i++) {
                    ps[i] = record.get(i);
                }
            }
            tslDataDao.batchInsertCemMobileExperienceList(list);
            log.debug("河北客户体验管理系统移网网络体验明细日信息 数据入库成功...");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("河北客户体验管理系统移网网络体验明细日信息..." + e.getMessage());
        }
    }

    private File getMobileComplaintDayFile(String day) {
        String fileName = tslDataProperties.getPrefixOfMobileComplaint() + day + ".csv";
        return Paths.get(tslDataProperties.getDirOfMobileComplaint(), fileName).toFile();
    }

    private File getHighQualityListDayFile(String day) {
        String fileName = tslDataProperties.getPrefixOfHighQualityListDay() + day + ".csv";
        return Paths.get(tslDataProperties.getDirOfHighQualityListDay(), fileName).toFile();
    }

    private File getHighQualityCountDayFile(String day) {
        String fileName = tslDataProperties.getPrefixOfHighQualityCountDay() + day + ".csv";
        return Paths.get(tslDataProperties.getDirOfHighQualityCountDay(), fileName).toFile();
    }

    // 河北客户体验管理智能定责投诉明细月累计接口日
    private File getComplaintDetailsFixYwdDayFile(String day) {
        String fileName = tslDataProperties.getPrefixOfComplaintDetailsFixYwdDay() + day + ".csv";
        return Paths.get(tslDataProperties.getDirOfComplaintDetailsFixYwdDay(), fileName).toFile();
    }

    // 河北客户体验管理系统移网网络体验明细日信息
    private File getCemMobileExperienceListFile(String day) {
        String fileName = tslDataProperties.getPrefixOfCemMobileExperienceList() + day + ".csv";
        return Paths.get(tslDataProperties.getDirOfCemMobileExperienceList(), fileName).toFile();
    }

    /**
     * 验证文件的MD5
     */
    private boolean checkMD5(File file) {
        String md5String = TextUtil.readLinesWithUTF8(file.getAbsolutePath() + ".MD5").get(0);
        String md5OfFile = CodecUtil.MD5OfFile(file);
        return md5String.equals(md5OfFile);
    }

    /**
     * 更新 ManagementDetail
     */
    public void updateManagementDetail(String day) {
        // 1. 检查是否已存在数据
        int countForDay = managementDetailMapper.selectCountofStatDay(day);
        if (countForDay != 0) {
            throw new RuntimeException(
                String.format("ManagementDetail 帐期 %s 已存在 %s 条数据", day, countForDay));
        }
        // 2. 入库新数据
        managementDetailMapper.insertFromMobileComplaint(day);
        managementDetailMapper.insertFromComplaintDetailsFixYwd(day);
    }

    /**
     * 删除 ManagementDetail
     */
    public int deleteManagementDetail(String day) {
        return managementDetailMapper.deleteForStatDay(day);
    }
}
