import { ChangeDetectorRef, Injectable } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { Subject } from "rxjs";
import { first, takeUntil } from "rxjs/operators";
import { MD2GameInfo, MD2Service } from "../../services/MD2/md2.service";
import { SignalRMessage } from "../../services/signal-r.service";
import { StateService } from "../../services/state.service";
import { ADIcon, MessageBoxConfig } from "../../ui/alert-dlg/alert-dlg.model";
import { MD2HeroInfo, MD2Icon, MobInfo, RoundPhase } from "./massive-darkness2.model";
import { LoginUserService } from "../../services/login-user.service";
import { GamePlayer } from "../games.model";

@Injectable()
export abstract class MD2Base {
    MD2Icon = MD2Icon;

    public get gameInfo() {
        return this.md2Service.info;
    }

    protected isHeroDashboard: boolean = false;
    protected roomId: string;
    protected destroy$: Subject<void> = new Subject<void>();
    /**
     *
     */
    constructor(
        protected md2Service: MD2Service,
        protected stateService: StateService,
        protected route: ActivatedRoute,
        protected cdRef: ChangeDetectorRef,
    ) {

    }
    ngOnInit(): void {
        this.route.paramMap.pipe(first()).subscribe(params => {
            if (params.get('roomId')) {
                this.roomId = params.get('roomId');
            }


        });
        this.md2Service.refreshUI$.pipe(takeUntil(this.destroy$)).subscribe(result => {
            this.cdRef.detectChanges();
        });
        this.stateService.loginUserService.signalRInitialized.pipe(first()).subscribe(result => {
            console.log('signalRInitialized');

            this.signalRInitialized();
        });
        this.md2Service.signalRService.ReceivedSignalRMessageSubject.pipe(takeUntil(this.destroy$)).subscribe(result => this.handleSignalRCallback(result));
    }

    ngOnDestroy() {
        this.destroy$.next();
        this.destroy$.complete();
    }
    signalRInitialized() {

    }

    imgUrl(imgPath: string) {
        return this.md2Service.imgUrl(imgPath);
    }
    fileList(folderPath: string) {
        return this.md2Service.fileList(folderPath);
    }

    iconHtml(icon: MD2Icon, cssClass = '') {
        return this.md2Service.iconHtml(icon, cssClass);
    }

    imgHtml(imgFile: string, cssClass = '') {
        return `<img src="${this.imgUrl(imgFile)}" class='${cssClass}'>`
    }
    detectChanges() {
        if (!this.cdRef['destroyed']) {
            this.cdRef.detectChanges();
            this.refreshUI();
            this.md2Service.refreshUI$.next();
        }

    }
    abstract refreshUI();
    handleSignalRCallback(message: SignalRMessage): void {
        if (message.from) {
            if (message.from.isGroup) {
                if (!this.isHeroDashboard) return;
            } else {
                if (this.isHeroDashboard && this.md2Service.playerHero?.playerInfo?.signalRClientId == message.from.connectionId) return;
            }
        }

        if (!this.isHeroDashboard) {

        }
        switch (message.actionType) {
            case 'hero':
                let heroInfo = new MD2HeroInfo(JSON.parse(message.parameters['hero']));
                switch (message.actionName) {
                    case 'join':
                        this.md2Service.heros.push(heroInfo);
                        break;
                    case 'update':
                        this.updateHeroInfo(heroInfo);
                        //Object.assign(heroInfo, exitingHero);
                        break;
                    case 'updateMyHero':
                        if (this.isHeroDashboard) {
                            this.md2Service.playerHero = heroInfo;
                        }

                        break;
                    default:
                        break;
                }
                this.detectChanges();
                break;
            case 'heroes':
                switch (message.actionName) {
                    case 'updateAll':
                        if (this.isHeroDashboard) {
                            let allHeroes = (JSON.parse(message.parameters['heros']) as MD2HeroInfo[]).map(h => new MD2HeroInfo(h));
                            //Remove heroes that are not in the list
                            this.md2Service.info.heros = this.md2Service.heros.filter(h => allHeroes.some(h2 => h2.playerInfo.tabId == h.playerInfo.tabId));
                            allHeroes.forEach(heroInfo => {
                                this.updateHeroInfo(heroInfo);
                            });
                            this.detectChanges();
                        }

                        break;
                }
                break;
            case 'GameRoom':
                switch (message.actionName) {
                    case 'Leaving':
                        let leavingPlayerInfo = message.value as GamePlayer;
                        let leavingHero = this.md2Service.heros.find(h => h.playerInfo.tabId == leavingPlayerInfo.tabId);
                        if (leavingHero) {
                            leavingHero.playerInfo.isDisconnected = true;
                        }
                        //var disconnectHero = this.md2Service.heros.splice(this.md2Service.heros.findIndex(h => h.playerInfo.signalRClientId == leavingPlayerInfo.signalRClientId));
                        //this.md2Service.info.disconnectedHeroes.push(...disconnectHero);
                        this.detectChanges();
                        break;
                    case 'update':
                        if (this.isHeroDashboard) {
                            this.md2Service.info = new MD2GameInfo(JSON.parse(message.parameters['gameInfo']) as MD2GameInfo);
                            let playerHero = this.md2Service.heros.find(h => h.playerInfo.tabId == this.stateService.loginUserService.sessionTabId);
                            if (playerHero) {

                                playerHero.playerInfo = this.md2Service.gameRoomService.currentPlayer();
                                playerHero.playerInfo.isDisconnected = false;
                                this.md2Service.playerHero = playerHero;
                                this.md2Service.broadcastMyHeroInfo();
                            }
                            this.detectChanges();
                        }
                        break;
                    case 'phase':
                        if (this.isHeroDashboard) {
                            this.md2Service.info.roundPhase = JSON.parse(message.parameters['phase']);
                            this.detectChanges();
                        }
                        break;
                    case 'getGameInfo':

                        if (!this.isHeroDashboard) {

                            this.md2Service.broadcastGameInfo();
                        }
                        break;
                    case 'sendJoinInfo':
                        if (this.isHeroDashboard && this.md2Service.playerHero) {
                            this.md2Service.playerHero.playerInfo.signalRClientId = message.parameters['signalrconnid'];
                            this.md2Service.broadcastMyHeroInfo();
                        }
                        break;
                    default:
                        break;
                }
                break;
            case 'message':
                switch (message.actionName) {
                    case 'popup':
                        let msg = JSON.parse(message.parameters['msg']) as MessageBoxConfig;
                        this.md2Service.msgBoxService.show(msg.title, msg);
                        break;
                    default:
                        break;
                }
                break;
            case 'roundPhase':
                switch (message.actionName) {
                    case 'bossFight':
                        this.gameInfo.isBossFight = true;
                        break;
                    default:
                        this.gameInfo.roundPhase = Number.parseInt(message.parameters['phase']);
                        break;
                }
                this.detectChanges();
                break;
            case 'mobs':
                if (this.isHeroDashboard) {
                    this.gameInfo.roamingMonsters = JSON.parse(message.parameters['roamingMonsters']);
                    this.gameInfo.mobs = JSON.parse(message.parameters['mobs']);
                    this.detectChanges();
                }
                break;
            case 'heroAction':
                if (!this.isHeroDashboard) {
                    //this.md2Service.currentActivateHero = this.md2Service.heros.find(h => h.playerInfo.tabId == message.parameters['tabId']);
                    switch (message.actionName) {
                        case 'attackAction':
                            if (this.gameInfo.isBossFight) {
                                this.md2Service.heroAttackingSubject.next(this.md2Service.currentActivateHero);
                            } else {
                                this.gameInfo.showAttackBtn = true;
                            }
                            break;
                        case 'openDoor':
                            //Door component listen for it
                            break;
                        case 'tradeAction':
                            this.md2Service.msgBoxService.show('Trade and Equip', {
                                text: `every one in the <b>same zone with ${this.md2Service.heroFullName(this.md2Service.currentActivateHero)}</b> may freely trade and 
                                equip items!`,
                                icon: ADIcon.INFO
                            });
                            break;
                        default:
                            //this.md2Service.roundPhase = Number.parseInt(message.parameters['phase']);
                            break;
                    }
                    this.heroAction(this.md2Service.currentActivateHero, message.actionName);
                    this.detectChanges();
                }
                break;
            default:
                break;
        }
    }
    updateHeroInfo(heroInfo: MD2HeroInfo) {
        let exitingHero = this.md2Service.heros.find(h => h.playerInfo.tabId == heroInfo.playerInfo.tabId);
        if (exitingHero) {
            //For boss fight, if the hero finished activating, activate the boss
            let activateBoss = exitingHero.uiActivating && !heroInfo.uiActivating;

            this.md2Service.heros[this.md2Service.heros.indexOf(exitingHero)] = heroInfo;
            //My hero update
            if (this.isHeroDashboard && this.md2Service.loginUserService.sessionTabId == heroInfo.playerInfo.tabId) {
                this.md2Service.playerHero = heroInfo;
            }
            if (!this.isHeroDashboard && this.md2Service.info.isBossFight && activateBoss) {
                this.md2Service.activateBoss();
            }
        } else {
            this.md2Service.heros.push(heroInfo);
        }
        if (!this.isHeroDashboard) {
            if (this.gameInfo.roundPhase == RoundPhase.HeroPhase) {
                if (!this.md2Service.heros.some(h => h.remainActions > 0) && !this.md2Service.heros.some(h => h.uiActivating)) {
                    if (!this.md2Service.info.isBossFight) {
                        if (this.md2Service.mobs.length > 0 || this.md2Service.roamingMonsters.length > 0) {
                            this.md2Service.msgBoxService.show('Enemy Phase', { icon: ADIcon.WARNING }).pipe(first()).subscribe(result => {
                                this.md2Service.runNextPhase();
                            });
                        } else {
                            this.md2Service.runNextPhase();
                        }
                    }


                }
            }
        }
    }

    abstract heroAction(hero: MD2HeroInfo, action: string);
}


@Injectable()
export abstract class MD2ComponentBase {
    protected roomId: string;
    protected destroy$: Subject<void> = new Subject<void>();
    /**
     *
     */
    constructor(
        protected md2Service: MD2Service,
        protected stateService: StateService,
        protected route: ActivatedRoute,
        protected cdRef: ChangeDetectorRef,
    ) {

    }
    ngOnInit(): void {
        this.md2Service.refreshUI$.pipe(takeUntil(this.destroy$)).subscribe(result => {
            this.cdRef.detectChanges();
        });
    }

    ngOnDestroy() {
        this.destroy$.next();
        this.destroy$.complete();
    }
    imgUrl(imgPath: string) {
        return this.md2Service.imgUrl(imgPath);
    }
    fileList(folderPath: string) {
        return this.md2Service.fileList(folderPath);
    }

    iconHtml(icon: MD2Icon, cssClass = '') {
        return this.md2Service.iconHtml(icon, cssClass);
    }
    detectChanges() {
        if (!this.cdRef['destroyed']) {
            this.cdRef.detectChanges();
            this.refreshUI();
            this.md2Service.refreshUI$.next();
        }

    }
    refreshUI() {

    }
}