import { JosaUtil, type RandUtil } from '@sammo-ts/common';

import type { General } from '@sammo-ts/logic/domain/entities.js';
import { getLegacyBattleItemIdentity, removeEquippedItem } from '@sammo-ts/logic/items/inventory.js';
import { LogFormat } from '@sammo-ts/logic/logging/types.js';
import { TriggerCaller, type Trigger } from '@sammo-ts/logic/triggers/core.js';
import type { WarUnit } from './units.js';

export interface WarTriggerContext {
    rng: RandUtil;
    attacker: WarUnit;
    defender: WarUnit;
}

export interface WarTriggerEnv {
    e_attacker: Record<string, unknown>;
    e_defender: Record<string, unknown>;
    stopNextAction?: boolean;
}

export type WarTrigger = Trigger<WarTriggerContext, WarTriggerEnv>;

export const createWarTriggerEnv = (): WarTriggerEnv => ({
    e_attacker: {},
    e_defender: {},
});

export class WarTriggerCaller extends TriggerCaller<WarTriggerContext, WarTriggerEnv> {}

export type WarTriggerFactory = (unit: WarUnit) => WarTrigger | WarTriggerCaller | null;

export type WarTriggerRegistry = Record<string, WarTriggerFactory>;

// 전투 트리거 공통 베이스. 전투 유닛 기준으로 동작하며, env는 공격/수비 분리 상태를 유지한다.
export abstract class BaseWarUnitTrigger implements WarTrigger {
    public static readonly TYPE_NONE = 0;
    public static readonly TYPE_ITEM = 1;
    public static readonly TYPE_CONSUMABLE_ITEM = 1 | 2;
    public static readonly TYPE_DEDUP_TYPE_BASE = 1024;

    protected readonly raiseType: number;

    protected constructor(
        protected readonly unit: WarUnit,
        public readonly priority: number,
        raiseType = BaseWarUnitTrigger.TYPE_NONE
    ) {
        this.raiseType = raiseType;
    }

    get uniqueId(): string {
        return `${this.priority}_${this.constructor.name}_${this.unit.getUnitId()}_${this.raiseType}`;
    }

    action(context: WarTriggerContext, env: WarTriggerEnv): WarTriggerEnv {
        const nextEnv: WarTriggerEnv = {
            e_attacker: env.e_attacker ?? {},
            e_defender: env.e_defender ?? {},
            ...(env.stopNextAction ? { stopNextAction: true } : {}),
        };

        if (nextEnv.stopNextAction) {
            return nextEnv;
        }

        const self = this.unit;
        const isAttacker = self.isAttacker();
        const oppose = isAttacker ? context.defender : context.attacker;

        const selfEnv = isAttacker ? nextEnv.e_attacker : nextEnv.e_defender;
        const opposeEnv = isAttacker ? nextEnv.e_defender : nextEnv.e_attacker;

        const shouldContinue = this.actionWar(self, oppose, selfEnv, opposeEnv);

        nextEnv.e_attacker = isAttacker ? selfEnv : opposeEnv;
        nextEnv.e_defender = isAttacker ? opposeEnv : selfEnv;

        if (!shouldContinue) {
            nextEnv.stopNextAction = true;
        }

        return nextEnv;
    }

    // 실제 트리거 구현부는 여기서 처리한다.
    protected abstract actionWar(
        self: WarUnit,
        oppose: WarUnit,
        selfEnv: Record<string, unknown>,
        opposeEnv: Record<string, unknown>
    ): boolean;

    public processConsumableItem(): boolean {
        if (!(this.raiseType & BaseWarUnitTrigger.TYPE_ITEM)) {
            return false;
        }
        if (this.unit.hasActivatedSkill('아이템사용')) {
            return false;
        }
        this.unit.activateSkill('아이템사용');
        const unit = this.unit as WarUnit & {
            getGeneral?: () => General;
        };
        const general = unit.getGeneral?.();
        if (!general) {
            return false;
        }
        const item = getLegacyBattleItemIdentity(general);
        this.unit.activateSkill(item.name);
        if (this.raiseType !== BaseWarUnitTrigger.TYPE_CONSUMABLE_ITEM) {
            return false;
        }
        if (this.unit.hasActivatedSkill('아이템소모')) {
            return false;
        }
        this.unit.activateSkill('아이템소모');
        const josaUl = JosaUtil.pick(item.rawName, '을');
        this.unit.getLogger().pushGeneralActionLog(`<C>${item.name}</>${josaUl} 사용!`, LogFormat.PLAIN);
        removeEquippedItem(general, 'item');
        return true;
    }
}
