//! Page generation implementation

use anyhow::{Context, Result};
use std::fs;
use std::path::Path;

use crate::app::App;
use crate::ui::preview::{
    generate_component_code, generate_route_config, generate_translation_content,
};

/// Result of page generation
#[derive(Debug)]
pub struct GenerationResult {
    pub files_created: Vec<String>,
    pub files_updated: Vec<String>,
    pub success: bool,
    pub error: Option<String>,
}

/// Generate all files for the page
pub fn generate_page(app: &App) -> Result<GenerationResult> {
    let mut result = GenerationResult {
        files_created: Vec::new(),
        files_updated: Vec::new(),
        success: false,
        error: None,
    };

    // Validate input first
    if !app.is_valid() {
        result.error = Some("Invalid configuration - cannot generate".to_string());
        return Ok(result);
    }

    // Create backup list for rollback
    let mut created_files = Vec::new();

    match generate_all_files(app, &mut created_files, &mut result) {
        Ok(()) => {
            result.success = true;
        }
        Err(e) => {
            // Rollback on error
            rollback_files(&created_files);
            result.error = Some(e.to_string());
        }
    }

    Ok(result)
}

/// Generate all required files
fn generate_all_files(
    app: &App,
    created_files: &mut Vec<String>,
    result: &mut GenerationResult,
) -> Result<()> {
    let project_root = &app.project_root;

    // 1. Generate route configuration
    generate_route_file(app, project_root, created_files, result)
        .context("Failed to generate route configuration")?;

    // 2. Generate component files (if auto-scaffold enabled)
    if app.auto_scaffold {
        generate_component_files(app, project_root, created_files, result)
            .context("Failed to generate component files")?;
    }

    // 3. Generate translation files
    generate_translation_files(app, project_root, created_files, result)
        .context("Failed to generate translation files")?;

    Ok(())
}

/// Generate route configuration file
fn generate_route_file(
    app: &App,
    project_root: &Path,
    created_files: &mut Vec<String>,
    result: &mut GenerationResult,
) -> Result<()> {
    let routes_dir = project_root.join("content").join("routes");
    fs::create_dir_all(&routes_dir).context("Failed to create routes directory")?;

    let route_file = routes_dir.join("generated_pages.toml");
    let route_config = generate_route_config(app);

    let file_existed = route_file.exists();

    if file_existed && !app.replace_existing {
        // Append to existing file
        let existing_content =
            fs::read_to_string(&route_file).context("Failed to read existing route file")?;
        let new_content = format!("{}\n\n{}", existing_content.trim(), route_config);
        fs::write(&route_file, new_content).context("Failed to append to route file")?;
        result.files_updated.push(route_file.display().to_string());
    } else {
        // Create or replace file
        fs::write(&route_file, &route_config).context("Failed to write route file")?;
        if file_existed {
            result.files_updated.push(route_file.display().to_string());
        } else {
            result.files_created.push(route_file.display().to_string());
            created_files.push(route_file.display().to_string());
        }
    }

    Ok(())
}

/// Generate component files
fn generate_component_files(
    app: &App,
    project_root: &Path,
    created_files: &mut Vec<String>,
    result: &mut GenerationResult,
) -> Result<()> {
    let module_name = app.page_name.to_lowercase();
    let pages_dir = project_root.join("crates").join("pages").join(&module_name);

    // Create module directory
    fs::create_dir_all(&pages_dir).context("Failed to create pages directory")?;

    // Generate mod.rs
    let mod_file = pages_dir.join("mod.rs");
    let mod_content = format!(
        r#"//! {} page module

pub mod unified;
pub use unified::*;
"#,
        app.page_name
    );

    if !mod_file.exists() || app.replace_existing {
        fs::write(&mod_file, mod_content).context("Failed to write mod.rs")?;
        if mod_file.exists() && !app.replace_existing {
            result.files_updated.push(mod_file.display().to_string());
        } else {
            result.files_created.push(mod_file.display().to_string());
            created_files.push(mod_file.display().to_string());
        }
    }

    // Generate unified.rs (main component)
    let component_file = pages_dir.join("unified.rs");
    let component_code = generate_component_code(app);

    if !component_file.exists() || app.replace_existing {
        fs::write(&component_file, component_code).context("Failed to write component file")?;
        if component_file.exists() && !app.replace_existing {
            result
                .files_updated
                .push(component_file.display().to_string());
        } else {
            result
                .files_created
                .push(component_file.display().to_string());
            created_files.push(component_file.display().to_string());
        }
    }

    Ok(())
}

/// Generate translation files for all selected languages
fn generate_translation_files(
    app: &App,
    project_root: &Path,
    created_files: &mut Vec<String>,
    result: &mut GenerationResult,
) -> Result<()> {
    let site_i18_path =
        std::env::var("SITE_LOCALES_PATH").unwrap_or_else(|_| "site/i18n".to_string());
    let locales_dir = project_root.join(&site_i18_path).join("locales");

    for lang_code in &app.selected_languages() {
        let lang_dir = locales_dir.join(lang_code);
        fs::create_dir_all(&lang_dir).context("Failed to create language directory")?;

        let translation_file = lang_dir.join(format!("{}.ftl", app.page_name.to_lowercase()));
        let translation_content = generate_translation_content(app, lang_code);

        let file_existed = translation_file.exists();

        if !file_existed || app.replace_existing {
            fs::write(&translation_file, translation_content)
                .context("Failed to write translation file")?;

            if file_existed {
                result
                    .files_updated
                    .push(translation_file.display().to_string());
            } else {
                result
                    .files_created
                    .push(translation_file.display().to_string());
                created_files.push(translation_file.display().to_string());
            }
        }
    }

    Ok(())
}

/// Rollback created files on generation failure
fn rollback_files(created_files: &[String]) {
    for file_path in created_files.iter().rev() {
        if let Err(e) = fs::remove_file(file_path) {
            eprintln!("Warning: Failed to rollback file {}: {}", file_path, e);
        }
    }

    // Also try to remove empty directories
    for file_path in created_files {
        if let Some(parent) = Path::new(file_path).parent() {
            let _ = fs::remove_dir(parent); // Ignore errors, directory might not be empty
        }
    }
}

/// Show generation progress
pub struct GenerationProgress {
    pub current_step: String,
    pub completed_steps: usize,
    pub total_steps: usize,
    pub files_processed: usize,
}

impl GenerationProgress {
    pub fn new(total_steps: usize) -> Self {
        Self {
            current_step: String::new(),
            completed_steps: 0,
            total_steps,
            files_processed: 0,
        }
    }

    pub fn update(&mut self, step: String) {
        self.current_step = step;
        self.completed_steps += 1;
    }

    pub fn progress_percent(&self) -> f32 {
        if self.total_steps == 0 {
            100.0
        } else {
            (self.completed_steps as f32 / self.total_steps as f32) * 100.0
        }
    }
}
