import { Type, type Static } from '../typebox';
import type { EvalContext } from './core/world';

// ── Shared ────────────────────────────────────────────────────────────────────

const RPGActionScheme = Type.Union([
    Type.Object({
        type: Type.String(),
        arg: Type.Optional(Type.Any()),
    }),
    Type.String(),
]);

export type RPGCondition = string;
export type RPGVariables = Record<string, string | number | boolean | undefined>;
export type RPGActions = Record<string, (arg?: any, ctx?: EvalContext) => unknown>;
export type RPGAction = Static<typeof RPGActionScheme>;


// ── Dialog ────────────────────────────────────────────────────────────────────

const DialogChoiceScheme = Type.Object({
    text: Type.String(),
    nextNodeId: Type.Optional(Type.String()),
});

const DialogNodeScheme = Type.Object({
    id: Type.String(),
    speaker: Type.String(),
    text: Type.String(),
    nextNodeId: Type.Optional(Type.String()),
    choices: Type.Optional(Type.Array(DialogChoiceScheme)),
    conditions: Type.Optional(Type.Array(Type.String())),
    actions: Type.Optional(Type.Array(RPGActionScheme)),
});

const DialogScheme = Type.Object({
    nodes: Type.Array(DialogNodeScheme),
    startNodeId: Type.String(),
});

export type DialogChoice = Static<typeof DialogChoiceScheme>;
export type DialogNode = Static<typeof DialogNodeScheme>;
export type Dialog = Static<typeof DialogScheme>;

export function isDialog(v: unknown): v is Dialog {
    return Type.Is(DialogScheme, v);
}

// ── Quest ─────────────────────────────────────────────────────────────────────

const QuestObjectiveScheme = Type.Object({
    id: Type.String(),
    description: Type.String(),
    condition: Type.String(),
});

const QuestStageScheme = Type.Object({
    id: Type.String(),
    description: Type.String(),
    objectives: Type.Array(QuestObjectiveScheme),
    actions: Type.Array(RPGActionScheme),
    failConditions: Type.Optional(Type.Array(Type.String())),
});

const QuestScheme = Type.Object({
    id: Type.String(),
    title: Type.String(),
    description: Type.String(),
    conditions: Type.Optional(Type.Array(Type.String())),
    stages: Type.Array(QuestStageScheme),
});

export type QuestObjective = Static<typeof QuestObjectiveScheme>;
export type QuestStage = Static<typeof QuestStageScheme>;
export type Quest = Static<typeof QuestScheme>;

export function isQuest(v: unknown): v is Quest {
    return Type.Is(QuestScheme, v);
}

// ── Inventory ─────────────────────────────────────────────────────────────────

export type SlotId = string | number;

export interface InventorySlotDefinition {
    slotId: SlotId;
    limit?: number;
}

export type InventorySlotInput = SlotId | InventorySlotDefinition;


