/**
 * 应用服务模块
 * @date 2022-03
 * @author 何华东
 */

import { logger } from "mslib";
import { Container, Inject, Singleton } from "typescript-ioc";
import { TyExternalApiClient, GetConfigInfoResponse } from "./TyExternalApi";
import { redisClient } from "./Redis";
import { Sync } from "./Promise";
import { IocConfigProvider } from "./Config";

let basic_config = IocConfigProvider.getBasicConfig();

/**
 * 车场扩展信息
 */
export type ParkExtendConfig = {
    /**
     * 固定返回字段`车场id`
     */
    stcParkId: any;

    /**
     * 车场id
     */
    parkId?: any;

    /**
     * 其他属性
     */
    [prop: string]: any;
}

/**
 * 对统一接口/接口授权抽象的应用服务类
 * 
 * `appId`、`appSecret`
 * 
 * @see [接口授权](https://kp-open.keytop.cn/api/index.html#/service/platformManage)
 */
@Singleton
export default class AppService {
    @Inject
    externalApiClient: TyExternalApiClient;

    configInfo: GetConfigInfoResponse = null;
    refresh_configInfo_interval = null;

    /**
     * 获取应用配置信息，包括已授权车场的配置信息
     * 
     * @redis key=`{tapdId}_configInfo` 时间：30分钟
     * @sync 同步执行
     * @deprecated {@link getConfigInfoFromLocal}
     */
    @Sync()
    async getConfigInfo(): Promise<GetConfigInfoResponse> {
        if (!basic_config?.tapdId) throw new Error(`未配置tapdId`);

        let key = `${basic_config.tapdId}_configInfo`;

        try {
            let value = await redisClient.get(key);
            if (value !== null) return JSON.parse(value);
        } catch (error) {
            logger.error(error);
        }

        let configInfo = await this.externalApiClient.getConfigInfo();

        try {
            await redisClient.set(key, JSON.stringify(configInfo), 'ex', 60 * 30);
        } catch (error) {
            logger.error(error);
        }

        return configInfo;
    }

    /**
     * 从APP已授权的车场列表中查找对应车场id的车场扩展信息，如未找到则为空
     * 
     * @ref {@link getConfigInfo}
     * @param parkId 需要匹配的车场id
     * @deprecated {@link findParkExtendConfigFromLocal}
     */
    async findParkExtendConfig(parkId: any): Promise<ParkExtendConfig> {
        let configInfo = await this.getConfigInfo();
        return configInfo?.parkConfig?.find(s => s.stcParkId === parkId?.toString() || s.parkId?.toString() === parkId?.toString());
    }

    /**
     * 从APP已授权的车场列表中获取对应车场id的车场扩展信息，如未找到则会抛出异常
     * @ref {@link getConfigInfo}
     * @param parkId 需要匹配的车场id
     * @deprecated {@link getParkExtendConfigFromLocal}
     */
    async getParkExtendConfig(parkId: any): Promise<ParkExtendConfig> {
        let parkExtendConfig = await this.findParkExtendConfig(parkId);
        if (!parkExtendConfig) throw `未匹配到车场,parkId:${parkId}`;

        return parkExtendConfig;
    }

    /**
     * 获取应用配置信息，包括已授权车场的配置信息
     * 
     * 本地缓存(5分钟)
     */
    @Sync()
    async getConfigInfoFromLocal(): Promise<GetConfigInfoResponse> {
        if (this.configInfo) return this.configInfo;

        let configInfo = await this.externalApiClient.getConfigInfo();
        this.configInfo = configInfo;

        if (!this.refresh_configInfo_interval) {
            this.refresh_configInfo_interval = setInterval(async () => {
                try {
                    let configInfo = await this.externalApiClient.getConfigInfo();
                    this.configInfo = configInfo;
                } catch (error) {
                    logger.error(`定时刷新车场配置信息失败`, error);
                }
            }, 1000 * 60 * 5);
        }

        return this.configInfo;
    }

    /**
     * 从APP已授权的车场列表中查找对应车场id的车场扩展信息，如未找到则为空
     * 
     * @param parkId 需要匹配的车场id
     * @ref {@link getConfigInfoFromLocal}
     */
    async findParkExtendConfigFromLocal(parkId: any): Promise<ParkExtendConfig> {
        let configInfo = await this.getConfigInfoFromLocal();
        return configInfo?.parkConfig?.find(s => s.stcParkId === parkId?.toString() || s.parkId?.toString() === parkId?.toString());
    }

    /**
     * 从APP已授权的车场列表中获取对应车场id的车场扩展信息，如未找到则会抛出异常
     * 
     * @ref {@link getConfigInfoFromLocal}
     * @param parkId 需要匹配的车场id
     */
    async getParkExtendConfigFromLocal(parkId: any): Promise<ParkExtendConfig> {
        let config = await this.findParkExtendConfigFromLocal(parkId);
        if (!config) throw `未匹配到车场,parkId:${parkId}`;

        return config;
    }
}

export { AppService }