//! Embedded game data for builds without filesystem access.
//!
//! This module embeds card and deck data at compile time, useful for
//! Python bindings or other scenarios where filesystem access is limited.
//!
//! All three data directories are auto-discovered at compile time via
//! `include_dir!` — adding a new YAML or TOML file under `data/cards/`,
//! `data/commanders/`, or `data/decks/` requires no code changes here,
//! just a rebuild.

use crate::cards::{CardDatabase, CardDefinition, CommanderDefinition};
use crate::decks::{DeckDefinition, DeckRegistry};

use include_dir::{include_dir, Dir};

// Auto-discover every YAML file under data/cards/ and data/commanders/
// at compile time. New files are picked up automatically on the next build.
static CARDS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../../data/cards");
static COMMANDERS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../../data/commanders");

// Decks were already auto-discovered this way.
static DECKS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../../data/decks");

/// Wrapper struct for the faction card file format.
/// The YAML files have a structure like: { name: "Faction", cards: [...] }
#[derive(serde::Deserialize)]
struct FactionCards {
    cards: Vec<CardDefinition>,
}

/// Wrapper struct for the commander file format.
/// The YAML files have a structure like: { commanders: [...] }
#[derive(serde::Deserialize)]
struct CommanderFile {
    commanders: Vec<CommanderDefinition>,
}

/// Collect all cards from a `data/cards/` subtree into `out`.
fn collect_cards_from_dir(dir: &Dir, out: &mut Vec<CardDefinition>) -> Result<(), String> {
    for file in dir.files() {
        if file.path().extension().is_some_and(|e| e == "yaml" || e == "yml") {
            let yaml_str = file
                .contents_utf8()
                .ok_or_else(|| format!("Card file is not valid UTF-8: {}", file.path().display()))?;
            let faction_cards: FactionCards = serde_yaml::from_str(yaml_str)
                .map_err(|e| format!("Failed to parse {}: {}", file.path().display(), e))?;
            out.extend(faction_cards.cards);
        }
    }
    for subdir in dir.dirs() {
        collect_cards_from_dir(subdir, out)?;
    }
    Ok(())
}

/// Collect all commanders from a `data/commanders/` subtree into `out`.
fn collect_commanders_from_dir(dir: &Dir, out: &mut Vec<CommanderDefinition>) -> Result<(), String> {
    for file in dir.files() {
        if file.path().extension().is_some_and(|e| e == "yaml" || e == "yml") {
            let yaml_str = file
                .contents_utf8()
                .ok_or_else(|| format!("Commander file is not valid UTF-8: {}", file.path().display()))?;
            let commander_file: CommanderFile = serde_yaml::from_str(yaml_str)
                .map_err(|e| format!("Failed to parse {}: {}", file.path().display(), e))?;
            out.extend(commander_file.commanders);
        }
    }
    for subdir in dir.dirs() {
        collect_commanders_from_dir(subdir, out)?;
    }
    Ok(())
}

/// Load the complete card database from embedded YAML data.
///
/// Auto-discovers every `.yaml` file under `data/cards/` (recursively) at compile time.
/// Adding a new card file requires no code changes — just drop the `.yaml` and rebuild.
pub fn load_embedded_cards() -> Result<CardDatabase, String> {
    let mut all_cards = Vec::with_capacity(320);
    collect_cards_from_dir(&CARDS_DIR, &mut all_cards)?;
    Ok(CardDatabase::new(all_cards))
}

/// Load the complete card database with commanders from embedded data.
///
/// Auto-discovers all `.yaml` files under `data/cards/` and `data/commanders/`
/// at compile time. Adding new files requires no code changes — just rebuild.
pub fn load_embedded_cards_with_commanders() -> Result<CardDatabase, String> {
    let mut all_cards = Vec::with_capacity(320);
    collect_cards_from_dir(&CARDS_DIR, &mut all_cards)?;

    let mut all_commanders = Vec::with_capacity(16);
    collect_commanders_from_dir(&COMMANDERS_DIR, &mut all_commanders)?;

    Ok(CardDatabase::new_with_commanders(all_cards, all_commanders))
}

/// Load all embedded decks into a DeckRegistry.
///
/// Auto-discovers every `.toml` file under `data/decks/` (recursively) at compile time.
/// Adding a new deck file requires no code changes — just drop the `.toml` and rebuild.
pub fn load_embedded_decks() -> Result<DeckRegistry, String> {
    let mut registry = DeckRegistry::new();
    collect_decks_from_dir(&DECKS_DIR, &mut registry)?;
    Ok(registry)
}

fn collect_decks_from_dir(dir: &Dir, registry: &mut DeckRegistry) -> Result<(), String> {
    for file in dir.files() {
        if file.path().extension().is_some_and(|e| e == "toml") {
            let toml_str = file.contents_utf8()
                .ok_or_else(|| format!("Deck file is not valid UTF-8: {}", file.path().display()))?;
            let deck: DeckDefinition = toml::from_str(toml_str)
                .map_err(|e| format!("Failed to parse deck {}: {}", file.path().display(), e))?;
            registry.add(deck)
                .map_err(|e| format!("Failed to add deck {}: {}", file.path().display(), e))?;
        }
    }
    for subdir in dir.dirs() {
        collect_decks_from_dir(subdir, registry)?;
    }
    Ok(())
}

/// Load both cards and decks from embedded data.
pub fn load_embedded_game_data() -> Result<(CardDatabase, DeckRegistry), String> {
    let cards = load_embedded_cards()?;
    let decks = load_embedded_decks()?;
    Ok((cards, decks))
}
