import { Client, Producer, Message, MessageId } from "pulsar-client";
import { Container, Scope, Singleton, Inject } from "typescript-ioc";
import { PulsarMasterFactory } from "../pulsar/PulsarMasterFactory";
import { PulsarSlaveFactory } from "../pulsar/PulsarSlaveFactory";
import { BaseEventHandler } from "./BaseEventHandler";
import { Payload } from "../model/Payload";
import { RedisUtil } from '../redis/RedisUtil';
import { Config } from '../config/Config'
import { OpResult } from '../config/OpResult'
import { log4js as logger } from '../log4js/logger'


@Singleton
export class Consumer {
    @Inject
    private pulsarMasterFactory: PulsarMasterFactory;

    @Inject
    private pulsarSlaveFactory: PulsarSlaveFactory;

    async consume(payload: Payload, baseEventHandler: BaseEventHandler) {
        logger.info('准备开始消费 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
        let masterClient = await this.pulsarMasterFactory.get();
        logger.info('从master pulsar消费 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
        await this.consumeFromPulsar(masterClient, payload, baseEventHandler)

        logger.info('从slave pulsar消费 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
        let slaveClient = await this.pulsarSlaveFactory.get();
        await this.consumeFromPulsar(slaveClient, payload, baseEventHandler)
    }

    private async consumeFromPulsar(client: Client, payload: Payload, baseEventHandler: BaseEventHandler) {
        // const redsiLock = Container.get(RedisUtil)
        let defaultTopic: string = `persistent://${Config.getDefaultTenant()}/${Config.getDefaultNamespace()}/${payload.getTopic()}`;
        let countAllConsumers: number = 0
        let costTime: number = 0
        await client.subscribe({
            topic: defaultTopic,
            subscription: Config.getSubscriptionId(),
            subscriptionType: 'Shared',
            ackTimeoutMs: 10000,
            listener: async (msg, msgConsumer) => {
                let time1 = Date.now()
                let checkParamResult = await this.checkParam(msg)
                if (!checkParamResult.isSuccess()) {
                    return
                }
                // let message: string = msg.getData().toString();
                // let msgId: string = JSON.parse(message).msgId
                //使用Redis分布式锁锁5秒
                try {
                    // const lock = await redsiLock.lock(msgId, 5000)
                    // if (!lock) {
                    //     logger.info('获取redis分布式锁失败....')
                    //     msgConsumer.acknowledge(msg);
                    //     return
                    // }
                    try {
                        await baseEventHandler.handle(msg)
                        msgConsumer.acknowledge(msg);
                    } catch (e) {
                        logger.error('执行事件处理器发生异常:' + e)
                    } finally {
                        // await redsiLock.unlock(lock)
                    }
                } catch (e) {
                    logger.error('redis加锁/解锁异常,不可提交。异常信息:' + e)
                }
                countAllConsumers++;
                let time2 = Date.now()
                costTime += (time2 - time1)
                logger.info(`总数：${countAllConsumers},总耗时：${costTime},单条耗时：${time2 - time1}`)
            },
        });
    }

    /**
     * 校验版本参数等是否符合
     * @param msg 
     * @returns 
     */
    async checkParam(msg): Promise<OpResult<any>> {
        let msgMajorVersion: Number = msg.getProperties()["majorVersion"];
        let projectMajorVersion: Number = Number(Config.getProjectMajorVersion());
        // logger.info(`msgMajorVersion:${msgMajorVersion},projectMajorVersion:${projectMajorVersion}`)
        if (msgMajorVersion != projectMajorVersion) {
            logger.info(`部署主版本与消息主版本不一致，不能消费....msgMajorVersion:${msgMajorVersion},projectMajorVersion:${projectMajorVersion}`)
            return OpResult.error('部署主版本与消息主版本不一致，不能消费')
        }
        let defaultRevisionVersion: string = Config.getDefaultVersions()[Config.getSubscriptionId()]
        // logger.info(`subscriptionId:${Config.getSubscriptionId()},defaultRevisionVersion:${defaultRevisionVersion}`)
        if (!defaultRevisionVersion) {
            logger.info(`当前部署没有默认版本，不能消费....subscriptionId:${Config.getSubscriptionId()},defaultRevisionVersion:${defaultRevisionVersion}`)
            return OpResult.error('当前部署没有默认版本，不能消费')
        }
        let projectRevisionVersion: string = Config.getProjectVersion()
        if (projectRevisionVersion != defaultRevisionVersion) {
            logger.info(`当前部署非默认版本，不能消费...projectRevisionVersion:${projectRevisionVersion},defaultRevisionVersion:${defaultRevisionVersion}`)
            return OpResult.error('当前部署非默认版本，不能消费')
        }
        return OpResult.success('success')
    }
}