import type { MAIN_STATS, ABILITIES, LEVELS, TRAINING_LEVELS, SPELL_TYPES, CATEGORIES, SPELL_ELEMENTS, ALIGNMENTS, RESISTANCES, DAMAGE_TYPES, WEAPON_TYPES } from "#shared/character.util";
import type { Localized } from "../types/general";

export type MainStat = typeof MAIN_STATS[number];
export type Ability = typeof ABILITIES[number];
export type Level = typeof LEVELS[number];
export type TrainingLevel = typeof TRAINING_LEVELS[number];
export type SpellType = typeof SPELL_TYPES[number];
export type Category = typeof CATEGORIES[number];
export type SpellElement = typeof SPELL_ELEMENTS[number];
export type Alignment = typeof ALIGNMENTS[number];
export type Resistance = typeof RESISTANCES[number];
export type DamageType = typeof DAMAGE_TYPES[number];
export type WeaponType = typeof WEAPON_TYPES[number];

export type FeatureID = string;
export type i18nID = string;

export type RecursiveKeyOf<TObj extends object> = {
  [TKey in keyof TObj & (string | number)]:
    TObj[TKey] extends any[] ? `${TKey}` :
    TObj[TKey] extends object
      ? `${TKey}` | `${TKey}/${RecursiveKeyOf<TObj[TKey]>}`
      : `${TKey}`;
}[keyof TObj & (string | number)];

export type Character = {
    id: number;

    name: string; //Free text
    people?: string; //People ID
    level: number;
    aspect?: number;
    notes?: { public?: string, private?: string }; //Free text

    training: Record<MainStat, Partial<Record<TrainingLevel, number>>>;
    leveling: Partial<Record<Level, number>>;
    abilities: Partial<Record<Ability, number>>;
    variables: CharacterVariables;
    choices: Record<FeatureID, number[]>;

    owner: number;
    username?: string;
    visibility: "private" | "public";
};
export type CharacterVariables = {
    health: number;
    mana: number;
    exhaustion: number;
    
    sickness: Array<{ id: string, state: number | true }>;
    poisons: Array<{ id: string, state: number | true }>;
    spells: string[]; //Spell ID
    items: ItemState[];
};
type ItemState = {
    id: string;
    amount: number;
    enchantments?: [];
    charges?: number;
    equipped?: boolean;
    state?: any;
};
export type CharacterConfig = {
    peoples: Record<string, RaceConfig>;
    training: Record<MainStat, Record<TrainingLevel, FeatureID[]>>;
    spells: SpellConfig[];
    aspects: AspectConfig[];
    features: Record<FeatureID, Feature>;
    enchantments: Record<string, EnchantementConfig>; //TODO
    items: Record<string, ItemConfig>;
    sickness: Record<string, { id: string, name: string, description: string, effect: FeatureID[] }>;
    action: Record<string, { id: string, name: string, description: string, cost: number }>;
    reaction: Record<string, { id: string, name: string, description: string, cost: number }>;
    freeaction: Record<string, { id: string, name: string, description: string }>;
    passive: Record<string, { id: string, name: string, description: string }>;
    texts: Record<i18nID, Localized>;
};
export type EnchantementConfig = {
    name: string; //TODO -> TextID
    effect: Array<FeatureEquipment | FeatureValue | FeatureList>;
    power: number;
}
export type ItemConfig = CommonItemConfig & (ArmorConfig | WeaponConfig | WondrousConfig | MundaneConfig);
type CommonItemConfig = {
    id: string;
    name: string; //TODO -> TextID
    description: i18nID;
    rarity: 'common' | 'uncommon' | 'rare' | 'legendary';
    weight?: number; //Optionnal but highly recommended
    price?: number; //Optionnal but highly recommended
    capacity?: number; //Optionnal as most mundane items should not receive enchantments (potions, herbal heals, etc...)
    powercost?: number; //Optionnal
    charge?: number //Max amount of charges
    enchantments?: string[]; //Enchantment ID
    effects?: Array<FeatureValue | FeatureEquipment | FeatureList>;
    equippable: boolean;
    consummable: boolean;
}
type ArmorConfig = {
    category: 'armor';
    health: number;
    type: 'light' | 'medium' | 'heavy';
    absorb: { static: number, percent: number };
};
type WeaponConfig = {
    category: 'weapon';
    type: Array<WeaponType>;
    damage: {
        value: string; //Dice formula
        type: DamageType;
    };
};
type WondrousConfig = {
    category: 'wondrous';
};
type MundaneConfig = {
    category: 'mundane';
};
export type SpellConfig = {
    id: string;
    name: string; //TODO -> TextID
    rank: 1 | 2 | 3 | 4;
    type: SpellType;
    cost: number;
    speed: "action" | "reaction" | number;
    elements: Array<SpellElement>;
    description: string; //TODO -> TextID
    concentration: boolean;
    range: 'personnal' | number;
    tags?: string[];
};
export type RaceConfig = {
    id: string;
    name: string; //TODO -> TextID
    description: string; //TODO -> TextID
    options: Record<Level, FeatureID[]>;
};
export type AspectConfig = {
    name: string;
    description: string; //TODO -> TextID
    stat: MainStat | 'special';
    alignment: Alignment;
    magic: boolean;
    difficulty: number;
    physic: { min: number, max: number };
    mental: { min: number, max: number };
    personality: { min: number, max: number };
    options: FeatureItem[];
};

export type FeatureValue = {
    id: FeatureID;
    category: "value";
    operation: "add" | "set" | "min";
    property: RecursiveKeyOf<CompiledCharacter> | 'spec' | 'ability' | 'training';
    value: number | `modifier/${MainStat}` | false;
}
export type FeatureEquipment = {
    id: FeatureID;
    category: "value";
    operation: "add" | "set" | "min";
    property: 'weapon/damage/value' | 'armor/health' | 'armor/absorb/flat' | 'armor/absorb/percent';
    value: number | `modifier/${MainStat}` | false;
}
export type FeatureList = {
    id: FeatureID;
    category: "list";
    list: "spells" | "sickness" | "action" | "reaction" | "freeaction" | "passive";
    action: "add" | "remove";
    item: string;
};
export type FeatureChoice = {
    id: FeatureID;
    category: "choice";
    text: string; //TODO -> TextID
    settings?: { //If undefined, amount is 1 by default
        amount: number;
        exclusive: boolean; //Disallow to pick the same option twice
    };
    options: Array<{ text: string, effects: Array<FeatureValue | FeatureList> }>; //TODO -> TextID
};
export type FeatureItem = FeatureValue | FeatureList | FeatureChoice;
export type Feature = {
    id: FeatureID;
    description: string; //TODO -> TextID
    effect: FeatureItem[];
};

export type CompiledCharacter = {
    id: number;
    owner?: number;
    username?: string;
    name: string;
    health: number; //Max
    mana: number; //Max
    race: string;
    spellslots: number; //Max
    artslots: number; //Max
    spellranks: Record<SpellType, 0 | 1 | 2 | 3>;
    aspect: string; //ID
    speed: number | false;
    capacity: number | false;
    initiative: number;
    exhaust: number;
    itempower: number;

    action: number;
    reaction: number;

    variables: CharacterVariables,

    defense: {
        hardcap: number;
        static: number;
        activeparry: number;
        activedodge: number;
        passiveparry: number;
        passivedodge: number;
    };

    mastery: {
        strength: number;
        dexterity: number;
        shield: number;
        armor: number;
        multiattack: number;
        magicpower: number;
        magicspeed: number;
        magicelement: number;
        magicinstinct: number;
    };

    bonus: {
        defense: Partial<Record<MainStat, number>>;
        abilities: Partial<Record<Ability, number>>;
    }; //Any special bonus goes here
    resistance: Record<string, number>;

    modifier: Record<MainStat, number>;
    abilities: Partial<Record<Ability, number>>;
    level: number;
    lists: { [K in FeatureList['list']]?: string[] }; //string => ListItem ID

    notes: { public: string, private: string };
};