import { Component, type EvalContext, type World } from "../core/world";
import type { RPGAction } from "../types";
import { action, component, variable } from "../utils/decorators";
import { executeAction } from "../utils/variables";
import { Equippable } from "./equipment";

interface ItemState {
    name: string;
    description: string;
}

@component
export class Item extends Component<ItemState> {
    constructor(name = '', description = '') {
        super({ name, description });
    }

    get name(): string { return this.state.name; }
    get description(): string { return this.state.description; }
}

interface StackableState {
    maxStack: number;
}

@component
export class Stackable extends Component<StackableState> {
    constructor(maxStack: number) {
        super({ maxStack });
    }

    @variable get maxStack(): number { return this.state.maxStack; }
}

interface UsableState {
    actions: RPGAction[];
    consumeOnUse: boolean;
}

@component
export class Usable extends Component<UsableState> {
    constructor(actions: RPGAction[], consumeOnUse = true) {
        super({ actions, consumeOnUse });
    }

    @variable get consumeOnUse(): boolean { return this.state.consumeOnUse; }

    @action
    use(user: EvalContext): void {
        for (const action of this.state.actions) {
            executeAction(action, user);
        }
    }
}

export namespace Items {
    export interface RegisterOptions {
        maxStack?: number;
        description?: string;
        usable?: { actions: RPGAction[]; consumeOnUse?: boolean };
        equippable?: { slotType: string };
    }

    export function register(world: World, id: string, name?: string, options?: RegisterOptions) {
        const entity = world.createEntity(id);
        entity.add(new Item(name, options?.description));
        if (options?.maxStack !== undefined) {
            entity.add(new Stackable(options.maxStack));
        }
        if (options?.usable) {
            entity.add(new Usable(options.usable.actions, options.usable.consumeOnUse));
        }
        if (options?.equippable) {
            entity.add(new Equippable(options.equippable.slotType));
        }
        return entity;
    }
}
