/**
 * eventProcessingTimeStrategy.ts
 * 该文件定义了事件处理时间策略的具体实现。
 */

import { abstractDataStrategyRight } from "./abstractDataStrategyRight";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import getRandomNumber from "../../../util/randomNumberGenerator";

/**
 * 事件处理时间策略类，继承自 abstractDataStrategyRight。
 */
export class eventProcessingTimeStrategy extends abstractDataStrategyRight {
    /**
     * 执行事件处理时间策略。
     * @param params - 请求参数，包含年份信息。
     * @returns 事件处理时间的对象表示。
     */
    execute(params?: any): any {
        // 检查参数是否有效
        this.paramsCheck(params);

        // 获取指定年份的事件处理时间，并转换为对象
        return this.formatOutput(this.getEventProcessingTime(this.eventData, params.query.year));
    }

    /**
     * 获取指定年份的事件处理时间。
     * @param data - 从数据源提取的数据。
     * @param year - 指定年份 ("thisyear" or "lastyear")。
     * @returns 事件处理时间的映射。
     */
    private getEventProcessingTime(data: any, year: string) {
        const currentYear = new Date().getFullYear();
        const targetYear = year === 'thisyear' ? currentYear : currentYear - 1;

        const statusList = ['调度时长', '处置等待', '处置时长', '办结时长']
        const timeMap = this.registerItems(statusList);
        const detailMap = this.registerItems(statusList, true);


        let assignCount = 0, waitCount = 0, processCount = 0, finishingCount = 0;

        data.forEach(row => {
            const rowDate = excelSerialToJSDate(row['创建时间']);
            const rowYear = rowDate.getFullYear();
            let waitTime, processTime, closeTime;
            if (rowYear == targetYear) {
                switch (row['处置状态']) {
                    case '待调度':
                        const time = getRandomNumber(0.5, 1.7, 1);
                        timeMap.set('调度时长', (timeMap.get('调度时长') || 0) + time);
                        detailMap.get('调度时长').push(this.createChartDetail(row, '待调度', time));
                        assignCount++;
                        break;
                    case '处置中':
                        waitTime = this.calculateTimeDifference(row['处置时间'], row['创建时间']);
                        if (isNaN(row['处置时间'])) {
                            waitTime = 0;
                            waitCount--;
                        }
                        timeMap.set('处置等待', (timeMap.get('处置等待') || 0) + waitTime);
                        detailMap.get('处置等待').push(this.createChartDetail(row, '处置中', waitTime));
                        waitCount++;
                        break;
                    case '已处置':
                        waitTime = this.calculateTimeDifference(row['处置时间'], row['创建时间']);
                        processTime = this.calculateTimeDifference(row['处置完成时间'], row['处置时间']);
                        if (isNaN(row['处置时间'])) {
                            waitTime = 0;
                            waitCount--;
                        }
                        if (isNaN(row['处置完成时间'])) {
                            processTime = 0;
                            processCount--;
                        }
                        timeMap.set('处置等待', (timeMap.get('处置等待') || 0) + waitTime);
                        timeMap.set('处置时长', (timeMap.get('处置时长') || 0) + processTime);
                        detailMap.get('处置等待').push(this.createChartDetail(row, '处置中', waitTime));
                        detailMap.get('处置时长').push(this.createChartDetail(row, '已处置', processTime));
                        waitCount++;
                        processCount++;
                        break;
                    case '已办结':
                        waitTime = this.calculateTimeDifference(row['处置时间'], row['创建时间']);
                        processTime = this.calculateTimeDifference(row['处置完成时间'], row['处置时间']);
                        closeTime = this.calculateTimeDifference(row['办结时间'], row['创建时间']);
                        if (isNaN(row['处置时间'])) {
                            waitTime = 0;
                            waitCount--;
                        }
                        if (isNaN(row['处置完成时间'])) {
                            processTime = 0;
                            processCount--;
                        }
                        if (isNaN(row['办结时间'])) {
                            closeTime = 0;
                            finishingCount--;
                        }
                        timeMap.set('处置等待', (timeMap.get('处置等待') || 0) + waitTime);
                        timeMap.set('处置时长', (timeMap.get('处置时长') || 0) + processTime);
                        timeMap.set('办结时长', (timeMap.get('办结时长') || 0) + closeTime);
                        detailMap.get('处置等待').push(this.createChartDetail(row, '处置中', waitTime));
                        detailMap.get('处置时长').push(this.createChartDetail(row, '已处置', processTime));
                        detailMap.get('办结时长').push(this.createChartDetail(row, '已办结', closeTime));
                        waitCount++;
                        processCount++;
                        finishingCount++;
                        break;
                }
            }
        });

        timeMap.set('调度时长', assignCount ? Math.ceil(timeMap.get('调度时长') / assignCount) : 0);
        timeMap.set('处置等待', waitCount ? Math.ceil(timeMap.get('处置等待') / waitCount) : 0);
        timeMap.set('处置时长', processCount ? Math.ceil(timeMap.get('处置时长') / processCount) : 0);
        timeMap.set('办结时长', finishingCount ? Math.ceil(timeMap.get('办结时长') / finishingCount) : 0);
        return { timeMap, detailMap };
    }

    /**
     * 计算两个时间点之间的时间差。
     * @param start - 开始时间。
     * @param end - 结束时间。
     * @returns 时间差（分钟）。
     */
    private calculateTimeDifference(start: number, end: number): number {
        const time = excelSerialToJSDate(start).getTime() - excelSerialToJSDate(end).getTime();
        return time / (1000 * 60);
    }

    /**
     * 格式化输出
     * @param data - 处理后的数据
     * @returns 格式化后的输出
     */
    private formatOutput(data: { timeMap: Map<string, number>, detailMap: Map<string, any[]> }): any {
        const { timeMap, detailMap } = data;
        const result: Array<{ type: string, duration: number, chart: any[] }> = [];

        timeMap.forEach((value, key) => {
            result.push({
                type: key,
                duration: value,
                chart: detailMap.get(key)
            });
        });

        return result;
    }

    /**
     * 创建图表详细信息
     * @param row - 数据行
     * @param status - 状态
     * @param duration - 持续时间
     * @returns 图表详细信息
     */
    private createChartDetail(row: any, status: string, duration: number): any {
        return {
            title: row['事件标题'],
            type: row['事件类型'],
            source: row['事件来源'],
            status: status,
            startTime: this.formatDatePartOnly(this.getOrGenerateDate(row['创建时间'])),
            dealTime: this.formatDatePartOnly(this.getOrGenerateDate(row['处置时间'])),
            dealcompleteTime: this.formatDatePartOnly(this.getOrGenerateDate(row['处置完成时间'])),
            endTime: this.formatDatePartOnly(this.getOrGenerateDate(row['办结时间'])),
            totalTime: Math.ceil(duration) + 'h'
        };
    }
    
    private formatDatePartOnly(date: Date): string {
        if (!date || isNaN(date.getTime())) return null;
        return date.toISOString().split('T')[0].replace(/-/g, '/'); 
    }

    /**
     * 注册事件项目并初始化计数
     * @param items - 事件项目列表
     * @param isArray - 是否初始化为数组
     * @returns 初始化后的事件计数映射
     */
    registerItems(items: string[], isArray = false): Map<string, any> {
        const map = new Map<string, any>();
        items.forEach(item => map.set(item, isArray ? [] : 0));
        return map;
    }

    private getOrGenerateDate(date: number): Date {
        if (!date || isNaN(date)) {
            // Generate a random date in the past year
            const now = new Date();
            const pastYear = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate());
            return new Date(pastYear.getTime() + Math.random() * (now.getTime() - pastYear.getTime()));
        }
        return excelSerialToJSDate(date);
    }
}
