package com.common.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;

import java.util.ArrayList;

import java.util.List;
import java.util.Map;
import java.util.HashMap;
@Service
public class PartitionTableService {

    private static final Logger logger = LoggerFactory.getLogger(PartitionTableService.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final DateTimeFormatter SQL_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter DISPLAY_FORMATTER = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
    /**
     * 检查第二天的分区表状态
     */
    public PartitionTableStatus checkTomorrowPartitionTable() {
        PartitionTableStatus status = new PartitionTableStatus();

        try {
            LocalDate tomorrow = LocalDate.now().plusDays(1);
            String tableName = "syslog_normal_data_p_" + tomorrow.format(DATE_FORMATTER);

            status.setCheckDate(tomorrow);
            status.setTableName(tableName);
            status.setExists(isTableExists(tableName));

            if (!status.isExists()) {
                // 如果不存在，尝试创建
                boolean created = createDailyPartitionTable(tomorrow);
                status.setCreated(created);
                status.setMessage(created ? "分区表创建成功" : "分区表创建失败");
            } else {
                status.setCreated(false);
                status.setMessage("分区表已存在");
            }

            logger.info("第二天分区表检查完成: {}", status);

        } catch (Exception e) {
            status.setExists(false);
            status.setCreated(false);
            status.setMessage("检查过程中发生错误: " + e.getMessage());
            logger.error("检查第二天分区表失败: {}", e.getMessage(), e);
        }

        return status;
    }
    /**
     * 获取分区表统计信息
     */
    public Map<String, Object> getPartitionTableStats() {
        Map<String, Object> stats = new HashMap<>();

        try {
            // 统计总分区表数量
            String countSql = "SELECT COUNT(*) FROM information_schema.tables " +
                    "WHERE table_schema = 'public' AND table_name LIKE 'syslog_normal_data_%'";
            Integer totalCount = jdbcTemplate.queryForObject(countSql, Integer.class);
            stats.put("totalPartitionTables", totalCount != null ? totalCount : 0);

            // 获取最近创建的分区表
            String recentSql = "SELECT table_name FROM information_schema.tables " +
                    "WHERE table_schema = 'public' AND table_name LIKE 'syslog_normal_data_%' " +
                    "ORDER BY table_name DESC LIMIT 5";
            List<String> recentTables = jdbcTemplate.queryForList(recentSql, String.class);
            stats.put("recentTables", recentTables);

            // 检查明天分区表状态
            PartitionTableStatus tomorrowStatus = checkTomorrowPartitionTable();
            stats.put("tomorrowStatus", tomorrowStatus);

        } catch (Exception e) {
            logger.error("获取分区表统计信息失败: {}", e.getMessage());
            stats.put("error", e.getMessage());
        }

        return stats;
    }
    /**
     * 检查未来多天的分区表状态
     */
    public List<PartitionTableStatus> checkFuturePartitionTables(int days) {
        List<PartitionTableStatus> statusList = new ArrayList<>();

        for (int i = 1; i <= days; i++) {
            LocalDate checkDate = LocalDate.now().plusDays(i);
            String tableName = "syslog_normal_data_p_" + checkDate.format(DATE_FORMATTER);

            PartitionTableStatus status = new PartitionTableStatus();
            status.setCheckDate(checkDate);
            status.setTableName(tableName);
            status.setExists(isTableExists(tableName));
            status.setMessage(status.isExists() ? "已存在" : "未创建");

            statusList.add(status);
        }

        return statusList;
    }
    /**
     * 创建下个月的分区表
     */
    public void createNextMonthPartitionTable() {
        try {
            // 获取下个月的第一天
            LocalDate nextMonthFirstDay = LocalDate.now()
                    .plusMonths(1)
                    .with(TemporalAdjusters.firstDayOfMonth());

            // 创建下个月每天的分区表
            LocalDate currentDay = nextMonthFirstDay;
            LocalDate nextMonthLastDay = nextMonthFirstDay.with(TemporalAdjusters.lastDayOfMonth());

            while (!currentDay.isAfter(nextMonthLastDay)) {
                createDailyPartitionTable(currentDay);
                currentDay = currentDay.plusDays(1);
            }

            logger.info("成功创建下个月所有分区表");

        } catch (Exception e) {
            logger.error("创建分区表失败: {}", e.getMessage(), e);
        }
    }


    /**
     * 创建指定日期的分区表
     */
    public boolean createDailyPartitionTable(LocalDate date) {
        try {
            String tableName = "syslog_normal_data_p_" + date.format(DATE_FORMATTER);
            String nextDay = date.plusDays(1).format(SQL_DATE_FORMATTER);
            String currentDay = date.format(SQL_DATE_FORMATTER);

            String sql = String.format(
                    "CREATE TABLE IF NOT EXISTS %s PARTITION OF syslog_normal_data " +
                            "FOR VALUES FROM ('%s') TO ('%s')",
                    tableName, currentDay, nextDay
            );

            jdbcTemplate.execute(sql);
            logger.info("成功创建分区表: {}", tableName);
            return true;

        } catch (Exception e) {
            logger.error("创建分区表失败，日期: {}，错误: {}", date, e.getMessage());
            return false;
        }
    }
    /**
     * 检查表是否存在
     */
    public boolean isTableExists(String tableName) {
        try {
            String sql = "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = ?)";
            return jdbcTemplate.queryForObject(sql, Boolean.class, tableName);
        } catch (Exception e) {
            logger.error("检查表是否存在失败: {}", e.getMessage());
            return false;
        }
    }

    // ============================================================
    //  达梦(DM)存储过程方式创建分区表 — 下月预创建
    //  存储过程: CREATE_TABLE_DAILY_PARTITIONS(table_name, startDate, endDate)
    // ============================================================

    /** 需要创建月度分区的主表列表 */
    private static final String[] MONTHLY_PARTITION_TABLES = {
            "alarm",
            "alarm_visit",
            "syslog_normal_data",
            "syslog_normal_alarm",
            "syslog_non_normal_message"
    };

    /**
     * 通过达梦存储过程创建下个月所有分区表（5个主表）
     * 存储过程内部已处理"分区已存在"异常，可安全重复调用
     */
    public void createNextMonthPartitionsByProcedure() {
        LocalDate nextMonthFirstDay = LocalDate.now()
                .plusMonths(1)
                .withDayOfMonth(1);
        LocalDate nextMonthLastDay = nextMonthFirstDay
                .with(TemporalAdjusters.lastDayOfMonth());

        String startDate = nextMonthFirstDay.format(SQL_DATE_FORMATTER);
        String endDate = nextMonthLastDay.format(SQL_DATE_FORMATTER);

        logger.info("开始通过存储过程创建下月分区表: {} ~ {}", startDate, endDate);

        int successCount = 0;
        int failCount = 0;

        for (String tableName : MONTHLY_PARTITION_TABLES) {
            try {
                String sql = String.format(
                        "CALL CREATE_TABLE_DAILY_PARTITIONS('%s', '%s', '%s')",
                        tableName, startDate, endDate);
                jdbcTemplate.execute(sql);
                successCount++;
                logger.info("存储过程执行成功: 表={}, 日期范围={} ~ {}", tableName, startDate, endDate);
            } catch (Exception e) {
                failCount++;
                logger.error("存储过程执行失败: 表={}, 日期范围={} ~ {}, 错误={}",
                        tableName, startDate, endDate, e.getMessage(), e);
            }
        }

        logger.info("下月分区表创建完成: 成功={}, 失败={}, 总计={}",
                successCount, failCount, MONTHLY_PARTITION_TABLES.length);
    }

    /**
     * 获取下个月需要创建的分区表数量
     */
    public int getNextMonthPartitionCount() {
        LocalDate nextMonthFirstDay = LocalDate.now()
                .plusMonths(1)
                .with(TemporalAdjusters.firstDayOfMonth());
        LocalDate nextMonthLastDay = nextMonthFirstDay.with(TemporalAdjusters.lastDayOfMonth());
        return nextMonthLastDay.getDayOfMonth();
    }

    /**
     * 分区表状态类
     */
    public static class PartitionTableStatus {
        private LocalDate checkDate;
        private String tableName;
        private boolean exists;
        private boolean created;
        private String message;

        // Getter and Setter 方法
        public LocalDate getCheckDate() { return checkDate; }
        public void setCheckDate(LocalDate checkDate) { this.checkDate = checkDate; }

        public String getTableName() { return tableName; }
        public void setTableName(String tableName) { this.tableName = tableName; }

        public boolean isExists() { return exists; }
        public void setExists(boolean exists) { this.exists = exists; }

        public boolean isCreated() { return created; }
        public void setCreated(boolean created) { this.created = created; }

        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }

        public String getDisplayDate() {
            return checkDate != null ? checkDate.format(DISPLAY_FORMATTER) : "";
        }

        @Override
        public String toString() {
            return String.format("PartitionTableStatus{date=%s, table=%s, exists=%s, created=%s, message='%s'}",
                    getDisplayDate(), tableName, exists, created, message);
        }
    }
}