//! Import handler for project data from various formats
//!
//! Supports importing from JSON, CSV, TOML, and other formats.

#![allow(dead_code)]

use crate::handlers::export::ProjectExport;
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::path::Path;
use syntaxis_core::ExportFormat;

/// Import configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImportConfig {
    /// Source file path
    pub source_file: String,
    /// Import format
    pub format: String,
    /// Overwrite existing projects
    #[serde(default)]
    pub overwrite: bool,
    /// Skip validation
    #[serde(default)]
    pub skip_validation: bool,
    /// Dry run (preview without importing)
    #[serde(default)]
    pub dry_run: bool,
}

/// Import result for a single project
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImportResult {
    /// Project ID
    pub project_id: String,
    /// Project name
    pub project_name: String,
    /// Import status
    pub success: bool,
    /// Status message
    pub message: String,
    /// Validation errors if any
    #[serde(skip_serializing_if = "Vec::is_empty")]
    #[serde(default)]
    pub validation_errors: Vec<String>,
}

/// Batch import results
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchImportResults {
    /// Timestamp of import
    pub imported_at: String,
    /// Total projects processed
    pub total: usize,
    /// Successfully imported
    pub successful: usize,
    /// Failed imports
    pub failed: usize,
    /// Per-project results
    pub results: Vec<ImportResult>,
}

/// Import handler
pub struct ImportHandler;

impl ImportHandler {
    /// Import projects from file
    pub fn import_from_file(
        path: impl AsRef<Path>,
        format: ExportFormat,
        config: &ImportConfig,
    ) -> Result<BatchImportResults> {
        let content = std::fs::read_to_string(path)?;

        match format {
            ExportFormat::Json => Self::import_from_json(&content, config),
            ExportFormat::Csv => Self::import_from_csv(&content, config),
            ExportFormat::Toml => Self::import_from_toml(&content, config),
            ExportFormat::Yaml => Self::import_from_yaml(&content, config),
            ExportFormat::Markdown => Err(anyhow!("Cannot import from Markdown format")),
        }
    }

    /// Import from JSON format
    fn import_from_json(content: &str, config: &ImportConfig) -> Result<BatchImportResults> {
        // Try to parse as batch export first
        if let Ok(batch) = serde_json::from_str::<serde_json::Value>(content) {
            if batch.get("project_count").is_some() {
                // This is a batch export
                let projects: Vec<ProjectExport> =
                    serde_json::from_value(batch.get("projects").cloned().unwrap_or_default())?;
                return Self::process_imports(projects, config);
            } else if let Ok(project) = serde_json::from_str::<ProjectExport>(content) {
                // Single project
                return Self::process_imports(vec![project], config);
            }
        }

        Err(anyhow!("Invalid JSON format for import"))
    }

    /// Import from CSV format
    fn import_from_csv(content: &str, config: &ImportConfig) -> Result<BatchImportResults> {
        let mut projects = Vec::new();
        let lines: Vec<&str> = content.lines().collect();

        if lines.is_empty() {
            return Err(anyhow!("Empty CSV file"));
        }

        // Skip header line
        for line in lines.iter().skip(1) {
            let parts: Vec<&str> = line.split(',').collect();
            if parts.len() >= 6 {
                let project = ProjectExport {
                    id: parts[0].trim().to_string(),
                    name: parts[1].trim().to_string(),
                    project_type: parts[2].trim().to_string(),
                    current_phase: parts[3].trim().to_string(),
                    version: parts[4].trim().to_string(),
                    status: parts[5].trim().to_string(),
                    description: String::new(),
                    created_at: chrono::Local::now().to_rfc3339(),
                    updated_at: chrono::Local::now().to_rfc3339(),
                    tags: Vec::new(),
                    metadata: serde_json::json!({}),
                    checklist_items: Vec::new(),
                };
                projects.push(project);
            }
        }

        Self::process_imports(projects, config)
    }

    /// Import from TOML format
    fn import_from_toml(content: &str, config: &ImportConfig) -> Result<BatchImportResults> {
        let value: toml::Value = toml::from_str(content)?;

        if let Some(projects_array) = value.get("projects").and_then(|v| v.as_array()) {
            let projects: Result<Vec<ProjectExport>> = projects_array
                .iter()
                .map(|item| {
                    let proj_str = toml::to_string(item)?;
                    Ok(toml::from_str(&proj_str)?)
                })
                .collect();

            Self::process_imports(projects?, config)
        } else {
            // Try single project
            let project: ProjectExport = toml::from_str(content)?;
            Self::process_imports(vec![project], config)
        }
    }

    /// Import from YAML format
    fn import_from_yaml(_content: &str, _config: &ImportConfig) -> Result<BatchImportResults> {
        // YAML parsing would require yaml crate
        // For now, return error
        Err(anyhow!("YAML import not implemented (requires yaml crate)"))
    }

    /// Process imports and create results
    fn process_imports(
        projects: Vec<ProjectExport>,
        config: &ImportConfig,
    ) -> Result<BatchImportResults> {
        let mut results = Vec::new();
        let mut successful = 0;
        let mut failed = 0;
        let total = projects.len();

        for project in projects {
            let validation_errors = if !config.skip_validation {
                Self::validate_project(&project)
            } else {
                Vec::new()
            };

            let success = validation_errors.is_empty();
            if success {
                successful += 1;
            } else {
                failed += 1;
            }

            let message = if success {
                if config.dry_run {
                    format!("Would import project '{}'", project.name)
                } else {
                    format!("Imported project '{}'", project.name)
                }
            } else {
                format!("Failed to import project '{}'", project.name)
            };

            results.push(ImportResult {
                project_id: project.id,
                project_name: project.name,
                success,
                message,
                validation_errors,
            });
        }

        Ok(BatchImportResults {
            imported_at: chrono::Local::now().to_rfc3339(),
            total,
            successful,
            failed,
            results,
        })
    }

    /// Validate project data
    fn validate_project(project: &ProjectExport) -> Vec<String> {
        let mut errors = Vec::new();

        if project.id.is_empty() {
            errors.push("Project ID is required".to_string());
        }

        if project.name.is_empty() {
            errors.push("Project name is required".to_string());
        }

        if project.current_phase.is_empty() {
            errors.push("Project phase is required".to_string());
        }

        // Validate phase is known
        let valid_phases = [
            "planning",
            "design",
            "development",
            "testing",
            "deployment",
            "maintenance",
        ];
        if !valid_phases.contains(&project.current_phase.as_str()) {
            errors.push(format!("Unknown phase: {}", project.current_phase));
        }

        // Validate version format
        if !project.version.contains('.') {
            errors.push("Version should follow semantic versioning".to_string());
        }

        errors
    }

    /// Load import configuration
    pub fn load_config(path: impl AsRef<Path>) -> Result<ImportConfig> {
        let content = std::fs::read_to_string(path)?;
        let config = toml::from_str(&content)?;
        Ok(config)
    }

    /// Export results to file
    pub fn export_results(results: &BatchImportResults, path: impl AsRef<Path>) -> Result<()> {
        let content = serde_json::to_string_pretty(results)?;
        std::fs::write(path, content)?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn create_test_project() -> ProjectExport {
        ProjectExport {
            id: "test-1".to_string(),
            name: "Test Project".to_string(),
            project_type: "web".to_string(),
            description: "A test project".to_string(),
            current_phase: "design".to_string(),
            version: "1.0.0".to_string(),
            created_at: "2024-01-01T00:00:00Z".to_string(),
            updated_at: "2024-01-02T00:00:00Z".to_string(),
            tags: vec!["test".to_string()],
            status: "active".to_string(),
            metadata: serde_json::json!({}),
            checklist_items: Vec::new(),
        }
    }

    #[test]
    fn test_validate_project_success() {
        let project = create_test_project();
        let errors = ImportHandler::validate_project(&project);
        assert!(errors.is_empty());
    }

    #[test]
    fn test_validate_project_missing_id() {
        let mut project = create_test_project();
        project.id = String::new();
        let errors = ImportHandler::validate_project(&project);
        assert!(!errors.is_empty());
        assert!(errors[0].contains("ID is required"));
    }

    #[test]
    fn test_validate_project_missing_phase() {
        let mut project = create_test_project();
        project.current_phase = String::new();
        let errors = ImportHandler::validate_project(&project);
        assert!(errors.iter().any(|e| e.contains("phase is required")));
    }

    #[test]
    fn test_validate_project_invalid_phase() {
        let mut project = create_test_project();
        project.current_phase = "invalid_phase".to_string();
        let errors = ImportHandler::validate_project(&project);
        assert!(errors.iter().any(|e| e.contains("Unknown phase")));
    }

    #[test]
    fn test_validate_project_invalid_version() {
        let mut project = create_test_project();
        project.version = "1".to_string();
        let errors = ImportHandler::validate_project(&project);
        assert!(errors.iter().any(|e| e.contains("semantic versioning")));
    }

    #[test]
    fn test_import_config() {
        let config = ImportConfig {
            source_file: "import.json".to_string(),
            format: "json".to_string(),
            overwrite: true,
            skip_validation: false,
            dry_run: false,
        };

        assert!(config.overwrite);
        assert!(!config.skip_validation);
    }

    #[test]
    fn test_import_result_creation() {
        let result = ImportResult {
            project_id: "test-1".to_string(),
            project_name: "Test".to_string(),
            success: true,
            message: "Success".to_string(),
            validation_errors: Vec::new(),
        };

        assert!(result.success);
        assert!(result.validation_errors.is_empty());
    }
}
