//! Storybook CLI tool
//!
//! Commands:
//! - `sb validate <path>` - Parse and validate entire project
//! - `sb inspect <entity>` - Show fully resolved entity details
//! - `sb watch <path>` - Continuous validation on file changes

use std::path::PathBuf;

use clap::{
    Parser,
    Subcommand,
};
use miette::{
    IntoDiagnostic,
    Result,
};
use storybook::Project;

#[derive(Parser)]
#[command(name = "sb")]
#[command(about = "Storybook DSL tool", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Validate a storybook project or file
    Validate {
        /// Path to a .sb file or directory containing .sb files
        #[arg(default_value = ".")]
        path: PathBuf,
    },

    /// Inspect a specific entity
    Inspect {
        /// Entity name to inspect
        name: String,

        /// Path to the storybook project directory
        #[arg(short, long, default_value = ".")]
        path: PathBuf,
    },

    /// Watch a project for changes and re-validate
    Watch {
        /// Path to the storybook project directory
        #[arg(default_value = ".")]
        path: PathBuf,
    },
}

fn main() -> Result<()> {
    let cli = Cli::parse();

    match cli.command {
        | Commands::Validate { path } => validate(&path)?,
        | Commands::Inspect { name, path } => inspect(&name, &path)?,
        | Commands::Watch { path } => watch(&path)?,
    }

    Ok(())
}

fn validate(path: &PathBuf) -> Result<()> {
    println!("Validating storybook at: {}", path.display());

    let project = Project::load(path)?;

    let char_count = project.characters().count();
    let rel_count = project.relationships().count();
    let inst_count = project.institutions().count();
    let sched_count = project.schedules().count();
    let behavior_count = project.behaviors().count();
    let arc_count = project.life_arcs().count();

    println!("✓ Validation successful!");
    println!();
    println!("Project contents:");
    println!("  Characters:    {}", char_count);
    println!("  Relationships: {}", rel_count);
    println!("  Institutions:  {}", inst_count);
    println!("  Schedules:     {}", sched_count);
    println!("  Behaviors:     {}", behavior_count);
    println!("  Life Arcs:     {}", arc_count);

    Ok(())
}

fn inspect(name: &str, path: &PathBuf) -> Result<()> {
    println!("Loading project from: {}", path.display());

    let project = Project::load(path)?;

    // Try to find the entity as different types
    if let Some(character) = project.find_character(name) {
        println!("Character: {}", character.name);
        println!("Fields:");
        for (field_name, value) in &character.fields {
            println!("  {}: {:?}", field_name, value);
        }
        println!("Prose blocks:");
        for (tag, prose) in &character.prose_blocks {
            println!("  ---{}", tag);
            println!("{}", prose.content);
            println!("  ---");
        }
        return Ok(());
    }

    if let Some(relationship) = project.find_relationship(name) {
        println!("Relationship: {}", relationship.name);
        println!("Participants:");
        for participant in &relationship.participants {
            println!("  {}", participant.name.join("::"));
        }
        println!("Fields:");
        for (field_name, value) in &relationship.fields {
            println!("  {}: {:?}", field_name, value);
        }
        return Ok(());
    }

    if let Some(institution) = project.find_institution(name) {
        println!("Institution: {}", institution.name);
        println!("Fields:");
        for (field_name, value) in &institution.fields {
            println!("  {}: {:?}", field_name, value);
        }
        return Ok(());
    }

    println!("Entity '{}' not found in project", name);
    Ok(())
}

fn watch(path: &PathBuf) -> Result<()> {
    use std::sync::mpsc::channel;

    use notify::{
        Event,
        EventKind,
        RecursiveMode,
        Watcher,
    };

    println!("Watching for changes in: {}", path.display());
    println!("Press Ctrl+C to stop");
    println!();

    // Initial validation
    match Project::load(path) {
        | Ok(_) => println!("✓ Initial validation successful"),
        | Err(e) => println!("✗ Initial validation failed: {}", e),
    }

    let (tx, rx) = channel::<notify::Result<Event>>();

    let mut watcher = notify::recommended_watcher(tx).into_diagnostic()?;
    watcher
        .watch(path, RecursiveMode::Recursive)
        .into_diagnostic()?;

    for res in rx {
        match res {
            | Ok(event) => {
                // Only re-validate on write events for .sb files
                if matches!(event.kind, EventKind::Modify(_) | EventKind::Create(_)) &&
                    event
                        .paths
                        .iter()
                        .any(|p| p.extension().and_then(|s| s.to_str()) == Some("sb"))
                {
                    println!("\n--- Change detected, re-validating... ---");
                    match Project::load(path) {
                        | Ok(_) => println!("✓ Validation successful"),
                        | Err(e) => println!("✗ Validation failed: {}", e),
                    }
                }
            },
            | Err(e) => println!("Watch error: {:?}", e),
        }
    }

    Ok(())
}
