import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { DialogRef, DialogContentBase, DialogService } from '@progress/kendo-angular-dialog';
import { GridComponent, GridDataResult } from '@progress/kendo-angular-grid';
import { State } from '@progress/kendo-data-query';
import { first } from 'rxjs/operators';
import { MD2MobInfo, MD2MobLevelInfo, MD2MobSkill, MobSkillTarget, GameBundle } from '../../massive-darkness2.db.model';
import { MobType } from '../../massive-darkness2.model';
import { MobSkillType } from '../../massive-darkness2.model.boss';
import { MD2MobLevelInfoService, MD2MobSkillService } from '../../service/massive-darkness2.service';
import { MsgBoxService } from '../../../../services/msg-box.service';
import { MD2MobSkillEditorComponent } from '../md2-mob-skill-editor/md2-mob-skill-editor.component';
import { MD2MobLevelEditorComponent } from '../md2-mob-level-editor/md2-mob-level-editor.component';

@Component({
    selector: 'ngx-md2-mob-info-detail',
    templateUrl: './md2-mob-info-detail.component.html',
    styleUrls: ['./md2-mob-info-detail.component.scss']
})
export class MD2MobInfoDetailComponent extends DialogContentBase implements OnInit {
    MobSkillType = MobSkillType;
    @Input() public mobInfo: MD2MobInfo;
    @ViewChild('levelsGrid') levelsGrid: GridComponent;
    @ViewChild('skillsGrid') skillsGrid: GridComponent;

    public mobLevelInfos: MD2MobLevelInfo[] = [];
    public levelsData: GridDataResult = { data: [], total: 0 };
    public levelsState: State = {
        skip: 0,
        take: 10,
        sort: [],
        filter: {
            logic: 'and',
            filters: []
        }
    };
    public selectedLevelInfo: MD2MobLevelInfo | null = null;
    public skillsData: GridDataResult = { data: [], total: 0 };
    public skillsState: State = {
        skip: 0,
        take: 10,
        sort: [],
        filter: {
            logic: 'and',
            filters: []
        }
    };
    public isLoading: boolean = false;

    public skillTypes: Array<{ value: MobSkillType; text: string }> = [];
    public skillTargets: Array<{ value: MobSkillTarget | null; text: string }> = [];

    constructor(
        public dialog: DialogRef,
        private dialogService: DialogService,
        private mobLevelInfoService: MD2MobLevelInfoService,
        private mobSkillService: MD2MobSkillService,
        private msgBoxService: MsgBoxService
    ) {
        super(dialog);
    }

    ngOnInit(): void {
        if (this.mobInfo) {
            this.mobLevelInfos = this.mobInfo.mobLevelInfos || [];
            if (this.mobLevelInfos.length > 0) {
                this.selectLevelInfo(this.mobLevelInfos[0]);
            }
            this.loadSkills();
        }
        this.initializeEnums();
    }

    private initializeEnums(): void {
        // Initialize MobSkillType options
        Object.keys(MobSkillType).filter(key => isNaN(Number(key))).forEach(key => {
            this.skillTypes.push({
                value: MobSkillType[key] as MobSkillType,
                text: key
            });
        });

        // Initialize MobSkillTarget options
        this.skillTargets.push({ value: null, text: 'None' });
        Object.keys(MobSkillTarget).filter(key => isNaN(Number(key))).forEach(key => {
            this.skillTargets.push({
                value: MobSkillTarget[key] as MobSkillTarget,
                text: key
            });
        });
    }

    public selectLevelInfo(levelInfo: MD2MobLevelInfo): void {
        if (levelInfo.defenceInfo == null) {
            levelInfo.defenceInfo = { type: MobSkillType.Defense, blue: 0, green: 0, yellow: 0, orange: 0, red: 0, black: 0 };
        }
        if (levelInfo.attackInfo == null) {
            levelInfo.attackInfo = { type: MobSkillType.Attack, blue: 0, green: 0, yellow: 0, orange: 0, red: 0, black: 0 };
        }
        this.selectedLevelInfo = levelInfo;
        this.loadSkills();
    }

    public editLevelHandler(dataItem: MD2MobLevelInfo): void {
        if (!this.mobInfo) return;

        // Create a copy of the level info for editing
        const levelCopy: MD2MobLevelInfo = JSON.parse(JSON.stringify(dataItem));
        this.openLevelEditor(levelCopy, false);
    }

    public addLevelHandler(): void {
        if (!this.mobInfo) return;

        // Get the last level info (highest level) if any exists
        const lastLevel = this.mobLevelInfos.length > 0
            ? this.mobLevelInfos.reduce((prev, current) => (prev.level > current.level) ? prev : current)
            : null;

        // Calculate the next level number
        const nextLevel = lastLevel ? lastLevel.level + 2 : 1;
        let rewardTokens = 0;
        let actions = 1;


        let newLevel: MD2MobLevelInfo;

        if (lastLevel) {
            // Copy the last level's info as initial values
            newLevel = {
                id: this.generateLevelId(),
                level: nextLevel,
                mobInfoId: this.mobInfo.id,
                rewardTokens: rewardTokens,
                fixedRareTreasure: lastLevel.fixedRareTreasure ?? 0,
                fixedEpicTreasure: lastLevel.fixedEpicTreasure ?? 0,
                fixedLegendTreasure: lastLevel.fixedLegendTreasure ?? 0,
                fixedHp: lastLevel.fixedHp ?? 0,
                hpPerHero: lastLevel.hpPerHero ?? 0,
                actions: lastLevel.actions ?? actions,
                attackInfo: lastLevel.attackInfo
                    ? { ...lastLevel.attackInfo }
                    : { type: MobSkillType.Attack, yellow: null, orange: null, red: null, blue: null, green: null, black: null },
                alterAttackInfo: lastLevel.alterAttackInfo
                    ? { ...lastLevel.alterAttackInfo }
                    : null,
                defenceInfo: lastLevel.defenceInfo
                    ? { ...lastLevel.defenceInfo }
                    : { type: MobSkillType.Defense, yellow: null, orange: null, red: null, blue: null, green: null, black: null }
            };
        } else {
            // Default values if no levels exist
            newLevel = {
                id: this.generateLevelId(),
                level: nextLevel,
                mobInfoId: this.mobInfo.id,
                rewardTokens: rewardTokens,
                fixedRareTreasure: 0,
                fixedEpicTreasure: 0,
                fixedLegendTreasure: 0,
                fixedHp: 0,
                hpPerHero: 0,
                actions: actions,
                attackInfo: { type: MobSkillType.Attack, yellow: null, orange: null, red: null, blue: null, green: null, black: null },
                alterAttackInfo: { type: MobSkillType.Attack, yellow: null, orange: null, red: null, blue: null, green: null, black: null },
                defenceInfo: { type: MobSkillType.Defense, yellow: null, orange: null, red: null, blue: null, green: null, black: null }
            };
        }

        switch (this.mobInfo.type) {
            case MobType.Mob:
                newLevel.actions = 2;

                switch (nextLevel) {
                    case 1:
                    case 3:
                        newLevel.rewardTokens = 1;
                        break;
                    case 5:
                        newLevel.rewardTokens = 2;
                        break;
                }
                break;
            case MobType.Boss:
                newLevel.actions = 1;
                break;
            case MobType.RoamingMonster:
                newLevel.actions = 1;

                switch (nextLevel) {
                    case 1:
                        newLevel.rewardTokens = 2;
                        newLevel.fixedRareTreasure = 1;
                        newLevel.fixedEpicTreasure = 0;
                        newLevel.fixedLegendTreasure = 0;
                        break;
                    case 3:
                        newLevel.rewardTokens = 2;
                        newLevel.fixedRareTreasure = 0;
                        newLevel.fixedEpicTreasure = 1;
                        newLevel.fixedLegendTreasure = 0;
                        break;
                    case 5:
                        newLevel.rewardTokens = 0;
                        newLevel.fixedRareTreasure = 0;
                        newLevel.fixedEpicTreasure = 3;
                        newLevel.fixedLegendTreasure = 0;
                        break;
                }
                break;
        }
        this.openLevelEditor(newLevel, true);
    }

    private openLevelEditor(level: MD2MobLevelInfo, isNew: boolean): void {
        if (!this.mobInfo) return;

        const dialogRef = this.dialogService.open({
            title: isNew ? 'Add New Level' : 'Edit Level',
            content: MD2MobLevelEditorComponent,
            width: '80vw',
            height: 700
        });

        const editor = dialogRef.content.instance as MD2MobLevelEditorComponent;
        editor.isAdding = isNew;
        editor.data = level;
        editor.mobInfoId = this.mobInfo.id;
        editor.mobType = this.mobInfo.type;

        // Force model re-initialization after data is set
        setTimeout(() => {
            editor.initializeModel();
        }, 0);

        dialogRef.result.subscribe(result => {
            if (result && typeof result === 'object' && 'id' in result) {
                this.handleLevelSaved(result as MD2MobLevelInfo, isNew);
            }
        });
    }

    private handleLevelSaved(result: MD2MobLevelInfo, isNew: boolean): void {
        if (!this.mobInfo) return;

        if (isNew) {
            if (!this.mobInfo.mobLevelInfos) {
                this.mobInfo.mobLevelInfos = [];
            }
            result.attackInfo.black = 0;
            this.mobLevelInfos.push(result);
        } else {
            const index = this.mobLevelInfos.findIndex(l => l.id === result.id);
            if (index !== -1) {
                this.mobLevelInfos[index] = result;
                // Update selected level if it's the one being edited
                if (this.selectedLevelInfo?.id === result.id) {
                    this.selectedLevelInfo = result;
                    this.loadSkills();
                }
            }
        }
    }

    public removeLevelHandler({ dataItem }: { dataItem: MD2MobLevelInfo }): void {
        this.msgBoxService.showConfirmDeleteBox().pipe(first()).subscribe(answer => {
            if (answer === true) {
                this.isLoading = true;
                this.mobLevelInfoService.delete(dataItem.id).pipe(first()).subscribe(result => {
                    const index = this.mobLevelInfos.findIndex(l => l.id === dataItem.id);
                    if (index !== -1) {
                        this.mobLevelInfos.splice(index, 1);
                        // Clear selection if deleted level was selected
                        if (this.selectedLevelInfo?.id === dataItem.id) {
                            this.selectedLevelInfo = null;
                            this.loadSkills();
                        }
                    }
                    this.isLoading = false;
                });
            }
        });
    }

    public loadSkills(): void {
        if (this.mobInfo && this.mobInfo.skills) {
            // Filter skills by selected level if a level is selected
            let filteredSkills = this.mobInfo.skills.sort((a, b) => a.seq - b.seq);
            // if (this.selectedLevelInfo) {
            //     filteredSkills = this.mobInfo.skills.filter(s => s.level === this.selectedLevelInfo.level);
            // }
            this.skillsData = {
                data: filteredSkills,
                total: filteredSkills.length
            };
        } else {
            this.skillsData = { data: [], total: 0 };
        }
    }

    public addSkillHandler(): void {
        if (!this.mobInfo) return;

        // Get the last level info (highest level) if any exists
        const lastLevel = this.mobInfo.skills.length > 0
            ? this.mobInfo.skills.reduce((prev, current) => (prev.seq > current.seq) ? prev : current)
            : null;
        let seq = 0;
        let level = 1;
        let type = MobSkillType.Combat;

        if (lastLevel) {
            seq = lastLevel.seq + 1;
            level = lastLevel.level + 2;
            type = lastLevel.type;
        }
        const newSkill: MD2MobSkill = {
            id: this.generateId(),
            seq: seq,
            level: level,
            mobInfoId: this.mobInfo.id,
            type: type,
            skillTarget: lastLevel?.skillTarget || MobSkillTarget.Random,
            clawRoll: lastLevel?.clawRoll || 0,
            skillRoll: lastLevel?.skillRoll || 1,
            name: lastLevel?.name || 'Combat Skill',
            skillCondition: lastLevel?.skillCondition || '',
            description: lastLevel?.description || ''
        };

        this.openSkillEditor(newSkill, true);
    }

    public editSkillHandler(dataItem: MD2MobSkill): void {
        if (!this.mobInfo) return;

        // Create a copy of the skill for editing
        const skillCopy: MD2MobSkill = JSON.parse(JSON.stringify(dataItem));
        this.openSkillEditor(skillCopy, false);
    }

    private openSkillEditor(skill: MD2MobSkill, isNew: boolean): void {
        if (!this.mobInfo) return;

        const dialogRef = this.dialogService.open({
            title: isNew ? 'Add New Skill' : 'Edit Skill',
            content: MD2MobSkillEditorComponent,
            width: '80vw',
            height: 700
        });

        const editor = dialogRef.content.instance;
        editor.isAdding = isNew;
        editor.data = skill;
        editor.mobInfoId = this.mobInfo.id;
        editor.selectedLevel = this.selectedLevelInfo?.level || 1;

        // Force model re-initialization after data is set
        setTimeout(() => {
            editor.initializeModel();
        }, 0);

        dialogRef.result.subscribe(result => {
            if (result && typeof result === 'object' && 'id' in result) {
                this.handleSkillSaved(result as MD2MobSkill, isNew);
            }
        });
    }

    private handleSkillSaved(result: MD2MobSkill, isNew: boolean): void {
        if (!this.mobInfo) return;

        if (isNew) {
            if (!this.mobInfo.skills) {
                this.mobInfo.skills = [];
            }
            this.mobInfo.skills.push(result);
        } else {
            const index = this.mobInfo.skills?.findIndex(s => s.id === result.id);
            if (index !== undefined && index !== -1 && this.mobInfo.skills) {
                this.mobInfo.skills[index] = result;
            }
        }
        this.loadSkills();
    }

    public saveSkillHandler({ dataItem, isNew }: any): void {
        // This method is no longer used but kept for backward compatibility
        // Skills are now edited via dialog
    }

    public removeSkillHandler({ dataItem }: { dataItem: MD2MobSkill }): void {
        if (!this.mobInfo) return;

        this.msgBoxService.showConfirmDeleteBox().pipe(first()).subscribe(answer => {
            if (answer === true) {
                this.isLoading = true;
                this.mobSkillService.delete(dataItem.id).pipe(first()).subscribe(result => {
                    if (this.mobInfo.skills) {
                        const index = this.mobInfo.skills.findIndex(s => s.id === dataItem.id);
                        if (index !== -1) {
                            this.mobInfo.skills.splice(index, 1);
                        }
                        this.loadSkills();
                    }
                    this.isLoading = false;
                });
            }
        });
    }


    private generateId(): string {
        return 'skill_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
    }

    private generateLevelId(): string {
        return 'level_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
    }

    public getSkillTypeName(type: MobSkillType): string {
        return MobSkillType[type] || '';
    }

    public getSkillTargetName(target: MobSkillTarget | null): string {
        if (target === null) return 'None';
        return MobSkillTarget[target] || '';
    }

    public getMobTypeName(type: MobType): string {
        return MobType[type] || '';
    }

    public getGameBundleName(bundle: GameBundle): string {
        return GameBundle[bundle] || '';
    }

    public close(): void {
        this.dialog.close(true);
    }
}

