/**
 * sightVisitorFlowPerHourStrategy.ts
 * 该文件定义了每小时计算的游客流量策略的具体实现，获取制定景点在指定日期的每小时游客流量。
 */

import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import mapToObj from "../../../util/mapToObj";
import {abstractDataStrategyLeft} from "./abstractDataStrategyLeft";

/**
 * 每小时计算的游客流量策略类，继承自 abstractDataStrategyLeft。
 */
export class sightVisitorFlowByHourStrategy extends abstractDataStrategyLeft {

    /**
     * 执行每小时计算的游客流量策略。
     * @param params - 请求参数，包含景点和日期信息。
     * @returns 指定景点指定日期的每小时的游客流量。
     */
    execute(params?: any): any {
        if (!params || !params.query || !params.query.date || !params.query.sight) {
            throw new Error('Date and sight parameters are required.');
        }
        const sightData = this.extractor.getData(sightVisitorFlowByHourStrategy.FILENAME, sightVisitorFlowByHourStrategy.SHEETNAME);
        return mapToObj(this.getVisitorFlowByHour(sightData, params.query.sight, params.query.date));
    }

    /**
     * 获取指定日期的每小时游客流量。
     * @param data - 从数据源提取的数据。
     * @param date - 指定日期。
     * @param sight - 指定景点。
     * @returns 指定景点指定日期的每小时的游客流量映射。
     */
    private getVisitorFlowByHour(data: any, sight: string, date: string): Map<string, number> {
        const visitorCount: Map<string, number> = new Map();
        for (let hour = 1; hour <= 24; hour++) {
            const formattedHour = hour.toString().padStart(2, '0') + "时";
            visitorCount.set(formattedHour, 0);
        }

        data.forEach(row => {
            const rowDate = excelSerialToJSDate(row['游玩时间']);
            let rowDateString;
            try {
                rowDateString = rowDate.toISOString().split('T')[0];
            } catch (e) {
                rowDateString = 'invalid time';
            }
            const rowSight = row['景点名称'];
            rowDate.setHours(rowDate.getHours() - sightVisitorFlowByHourStrategy.TIMEDIFFERENCE);
            const rowHour = rowDate.getHours() + 1;
            const formattedHour = rowHour.toString().padStart(2, '0') + "时";

            if (rowDateString === date && rowSight === sight) {
                visitorCount.set(formattedHour, (visitorCount.get(formattedHour) || 0) + 1);
            }
        });

        // Randomly generate a value between 0 and 50 if the value is zero
        visitorCount.forEach((count, hour) => {
            if (count === 0) {
                visitorCount.set(hour, Math.floor(Math.random() * 51)); // Random number between 0 and 50
            }
        });

        return visitorCount;
    }
}
