//! Emit substrate — per-target codegen lives here.
//!
//! Every target implements `CodegenTarget` and returns the same shape:
//! a `Vec<EmittedFile>`. The dispatcher in `main.rs` iterates one target
//! per `--target` flag and writes each `EmittedFile` to disk under the
//! configured output directory.
//!
//! Targets land in subsequent phases; Phase 2 establishes the trait so
//! the dispatch surface is settled before any target's emit logic is
//! written.

use std::path::PathBuf;

use crate::config::Config;
use crate::ir::MizanIR;

pub mod casing;
pub mod channels;
pub mod python;
pub mod react;
pub mod rust;
pub mod stage1;
pub mod svelte;
pub mod vue;


pub trait CodegenTarget {
    /// Stable identifier — matches the `--target` flag value and the
    /// `targets = [...]` entry in `mizan.toml`.
    fn name(&self) -> &'static str;

    /// Walk the IR and produce the per-target file set. Each path is
    /// relative to the consumer's configured `output` directory.
    fn emit(&self, ir: &MizanIR, config: &Config) -> Vec<EmittedFile>;
}


pub struct EmittedFile {
    pub rel_path: PathBuf,
    pub content: String,
}


impl EmittedFile {
    pub fn new(rel_path: impl Into<PathBuf>, content: impl Into<String>) -> Self {
        Self {
            rel_path: rel_path.into(),
            content: content.into(),
        }
    }
}


/// Look up a registered target by name. Returns `None` for unknown
/// targets so the CLI can warn instead of panicking.
pub fn target_by_name(name: &str) -> Option<Box<dyn CodegenTarget>> {
    match name {
        "stage1" => Some(Box::new(stage1::Stage1)),
        "rust" => Some(Box::new(rust::RustCrate)),
        "python" => Some(Box::new(python::PythonClient)),
        "react" => Some(Box::new(react::ReactAdapter)),
        "vue" => Some(Box::new(vue::VueAdapter)),
        "svelte" => Some(Box::new(svelte::SvelteAdapter)),
        "channels" => Some(Box::new(channels::ChannelsTarget)),
        _ => None,
    }
}
