/**
 * 应用服务模块
 * @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 { Config, IocConfigProvider } from "./Config";
import { clearInterval } from "timers";

let basic_config = IocConfigProvider.getBasicConfig();

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

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

    /**
     * 第三方车场标识
     */
    thirdParkId?:any;

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

/**
 * 接口授权/`APP`应用服务, `appId`、`appSecret`
 * 
 * ```ts
 * import { AppService } from "refs/nslib";
 * import { Inject, Singleton } from "typescript-ioc";
 * 
 * //去掉注释
 * //@Inject
 * appService: AppService;
 * 
 * //获取APP的配置信息，包括已授权车场的扩展配置
 * let configInfo = await this.appService.getConfigInfoFromLocal();
 * ```
 * @see [接口授权](https://kp-open.keytop.cn/api/index.html#/service/platformManage)
 */
@Singleton
export default class AppService {
    @Inject
    externalApiClient: TyExternalApiClient;

    private configInfo: GetConfigInfoResponse;
    private refresh_configInfo_interval: NodeJS.Timer;

    /**
     * 获取`APP`的配置信息, 包括已授权车场的扩展配置
     * 
     * redis缓存(30分钟), key: `{tapdId}_configInfo`
     * 
     * @param ex 过期时间(秒)
     * @deprecated {@link getConfigInfoFromLocal}
     */
    @Sync()
    async getConfigInfo(ex: number = 60 * 30): 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', ex);
        } catch (error) {
            logger.error(error);
        }

        return configInfo;
    }

    /**
     * 从redis缓存 {@link getConfigInfo} 查找车场扩展配置
     * 
     * @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());
    }

    /**
     * 从redis缓存 {@link getConfigInfo} 获取车场扩展配置, 如果未匹配到则抛出异常
     * 
     * @throws {@link Error}
     * @deprecated {@link getParkExtendConfigFromLocal}
     */
    async getParkExtendConfig(parkId: any): Promise<ParkExtendConfig> {
        let parkExtendConfig = await this.findParkExtendConfig(parkId);
        if (!parkExtendConfig) throw new Error(`未匹配到车场,parkId:${parkId}`);

        return parkExtendConfig;
    }

    /**
     * 获取`APP`的配置信息, 包括已授权车场的扩展配置
     * 
     * 本地缓存(5分钟)
     * @param ex 过期时间(秒)
     */
    @Sync()
    async getConfigInfoFromLocal(ex?: number): Promise<GetConfigInfoResponse> {
        if (this.configInfo) return this.configInfo;

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

        if (this.refresh_configInfo_interval) clearInterval(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);
            }
        }, ex ? ex * 1000 : 1000 * 60 * 5);

        return this.configInfo;
    }

    /**
     * 从本地缓存 {@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());
    }

    /**
     * 从本地缓存 {@link getConfigInfoFromLocal} 获取车场扩展配置, 如果未匹配到则抛出异常
     * 
     * @throws {@link Error}
     */
    async getParkExtendConfigFromLocal(parkId: any): Promise<ParkExtendConfig> {
        let config = await this.findParkExtendConfigFromLocal(parkId);
        if (!config) throw new Error(`未匹配到车场,parkId:${parkId}`);

        return config;
    }

    /**
     * 根据第三方车场id thirdParkId来获取平台配置
     */
    async getParkExtendConfigByThirdParkId(thirdParkId: any): Promise<ParkExtendConfig> {
        let configInfo = await this.getConfigInfoFromLocal();
        let parkExtendConfig = configInfo?.parkConfig.find(s => s.thirdParkId?.toString() === thirdParkId.toString());
        if (!parkExtendConfig) throw `未匹配到车场扩展配置,thirdParkId：${thirdParkId}`;

        return parkExtendConfig;
    }
}

export { AppService }