//! Integration adapters for external tools

use crate::error::{LifecycleError, Result};
use crate::phase::ProjectPhase;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

/// Integration with doc-syntaxis
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DocLifecycleIntegration {
    /// Path to doc-syntaxis workspace
    pub workspace_path: PathBuf,
    /// Enable doc-lifecycle
    pub enabled: bool,
    /// Auto-update root files (README, CHANGELOG)
    pub auto_update_root_files: bool,
    /// Auto-generate mdbook
    pub auto_generate_mdbook: bool,
    /// Enable RAG indexing
    pub rag_enabled: bool,
    /// Phases where doc-lifecycle is active
    pub active_phases: Vec<ProjectPhase>,
}

impl DocLifecycleIntegration {
    /// Create new doc-lifecycle integration
    pub fn new(workspace_path: PathBuf) -> Self {
        Self {
            workspace_path,
            enabled: false,
            auto_update_root_files: true,
            auto_generate_mdbook: false,
            rag_enabled: false,
            active_phases: vec![
                ProjectPhase::Devel,
                ProjectPhase::Review,
                ProjectPhase::Publish,
            ],
        }
    }

    /// Enable integration
    pub fn enable(mut self) -> Self {
        self.enabled = true;
        self
    }

    /// Check if active in phase
    pub fn is_active_in_phase(&self, phase: ProjectPhase) -> bool {
        self.enabled && self.active_phases.contains(&phase)
    }

    /// Trigger doc-lifecycle classification
    pub fn trigger_classification(&self, docs_path: &PathBuf) -> Result<()> {
        if !self.enabled {
            return Ok(());
        }

        tracing::info!("Triggering doc-lifecycle classification at {:?}", docs_path);

        // Classification processes documents and categorizes them by type:
        // - API documentation
        // - Implementation guides
        // - User guides
        // - Tutorials
        // - Architecture docs
        // - Contributing guides
        //
        // In a full integration, this would call:
        // doc_lifecycle_plugin.classify_documents(docs_path).await?

        // For now, we validate that docs directory exists
        if !docs_path.exists() {
            tracing::warn!("Documentation directory does not exist: {:?}", docs_path);
            return Err(LifecycleError::integration(format!(
                "Documentation path does not exist: {:?}",
                docs_path
            )));
        }

        let doc_count = std::fs::read_dir(docs_path)
            .ok()
            .map(|entries| entries.count())
            .unwrap_or(0);

        tracing::info!("Classification triggered for {} documents", doc_count);

        Ok(())
    }

    /// Trigger documentation consolidation
    pub fn trigger_consolidation(&self) -> Result<()> {
        if !self.enabled {
            return Ok(());
        }

        tracing::info!("Triggering doc-lifecycle consolidation");

        // Consolidation detects duplicate documents and generates a consolidation report:
        // - Identifies similar documents
        // - Calculates similarity scores
        // - Suggests merging or archiving
        //
        // In a full integration, this would call:
        // let report = doc_lifecycle_plugin.consolidate_documents().await?;
        // report.save_to_file("consolidation_report.json")?;

        tracing::info!("Documentation consolidation analysis complete");

        Ok(())
    }

    /// Update root files (README, CHANGELOG)
    pub fn update_root_files(&self, readme_content: &str, changelog_content: &str) -> Result<()> {
        if !self.enabled || !self.auto_update_root_files {
            return Ok(());
        }

        tracing::info!(
            "Updating root files via doc-lifecycle (README: {} bytes, CHANGELOG: {} bytes)",
            readme_content.len(),
            changelog_content.len()
        );

        // Root files keeper automatically:
        // - Updates README.md with project overview
        // - Updates CHANGELOG.md with git commit history
        // - Updates ROADMAP.md with future plans
        // - Creates backups before modifying
        //
        // In a full integration, this would call:
        // keeper.update_readme(readme_content).await?;
        // keeper.update_changelog(changelog_content).await?;

        // Validate that content is provided
        if readme_content.is_empty() {
            tracing::warn!("README content is empty, skipping update");
            return Err(LifecycleError::integration(
                "README content cannot be empty".to_string(),
            ));
        }

        tracing::debug!("Root files update triggered with provided content");

        Ok(())
    }

    /// Generate mdbook documentation
    pub fn generate_mdbook(&self, docs_path: &PathBuf) -> Result<String> {
        if !self.enabled || !self.auto_generate_mdbook {
            return Ok(String::new());
        }

        tracing::info!("Generating mdbook documentation from {:?}", docs_path);

        // mdBook generation:
        // - Reads documentation from docs directory
        // - Generates SUMMARY.md with table of contents
        // - Builds static HTML site
        // - Outputs to book/ directory
        //
        // In a full integration, this would call:
        // let result = doc_lifecycle_plugin.generate_mdbook(docs_path).await?;
        // book_path = result.output_path

        // Validate that docs directory exists
        if !docs_path.exists() {
            tracing::warn!("Documentation directory does not exist: {:?}", docs_path);
            return Err(LifecycleError::integration(format!(
                "Documentation path does not exist: {:?}",
                docs_path
            )));
        }

        // Count markdown files for logging
        let md_count = std::fs::read_dir(docs_path)
            .ok()
            .map(|entries| {
                let count = entries
                    .filter_map(|e| e.ok())
                    .filter(|e| e.path().extension().map(|ext| ext == "md").unwrap_or(false))
                    .count();
                count
            })
            .unwrap_or(0);

        tracing::info!("Generating mdbook from {} markdown files", md_count);

        // Return path to generated book
        let book_path = self.workspace_path.join("book/index.html");

        Ok(book_path.to_string_lossy().to_string())
    }
}

/// Integration with tracking-manager
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrackingManagerIntegration {
    /// Path to tracking-manager workspace
    pub workspace_path: PathBuf,
    /// Enable tracking
    pub enabled: bool,
    /// Database path for tracking data
    pub db_path: PathBuf,
    /// Sync Claude TODOs
    pub sync_claude_todos: bool,
    /// Phases where tracking is active
    pub active_phases: Vec<ProjectPhase>,
}

impl TrackingManagerIntegration {
    /// Create new tracking integration
    pub fn new(workspace_path: PathBuf, db_path: PathBuf) -> Self {
        Self {
            workspace_path,
            enabled: false,
            db_path,
            sync_claude_todos: true,
            active_phases: vec![
                ProjectPhase::Devel,
                ProjectPhase::Update,
                ProjectPhase::Review,
            ],
        }
    }

    /// Enable integration
    pub fn enable(mut self) -> Self {
        self.enabled = true;
        self
    }

    /// Check if active in phase
    pub fn is_active_in_phase(&self, phase: ProjectPhase) -> bool {
        self.enabled && self.active_phases.contains(&phase)
    }

    /// Log a change to tracking system
    pub fn log_change(&self, summary: &str, impact: &str, change_type: &str) -> Result<String> {
        if !self.enabled {
            return Ok(String::new());
        }

        // Validate inputs
        if summary.is_empty() {
            return Err(LifecycleError::integration(
                "Change summary cannot be empty".to_string(),
            ));
        }

        // Validate change type
        let valid_types = [
            "feature", "bugfix", "refactor", "docs", "test", "chore", "perf",
        ];
        if !valid_types.contains(&change_type) {
            tracing::warn!(
                "Unknown change type: {}. Valid types: {:?}",
                change_type,
                valid_types
            );
        }

        // Validate impact level
        let valid_impacts = ["Critical", "High", "Medium", "Low"];
        if !valid_impacts.contains(&impact) {
            tracing::warn!(
                "Unknown impact level: {}. Valid levels: {:?}",
                impact,
                valid_impacts
            );
        }

        tracing::info!(
            "Logging change to tracking: {} ({}) [{}]",
            summary,
            change_type,
            impact
        );

        // In a full integration, this would call:
        // tracking_manager.log_change(ChangeEvent {
        //     summary,
        //     impact,
        //     change_type,
        //     timestamp: Utc::now(),
        // }).await?

        let change_id = format!("change-{}", chrono::Utc::now().timestamp());
        tracing::debug!("Change logged with ID: {}", change_id);

        Ok(change_id)
    }

    /// Add TODO item to tracking system
    pub fn add_todo(&self, summary: &str, priority: &str) -> Result<String> {
        if !self.enabled {
            return Ok(String::new());
        }

        // Validate inputs
        if summary.is_empty() {
            return Err(LifecycleError::integration(
                "TODO summary cannot be empty".to_string(),
            ));
        }

        // Validate priority
        let valid_priorities = ["Critical", "High", "Medium", "Low"];
        if !valid_priorities.contains(&priority) {
            return Err(LifecycleError::integration(format!(
                "Invalid priority: {}. Must be one of: {:?}",
                priority, valid_priorities
            )));
        }

        tracing::info!("Adding TODO to tracking: {} ({})", summary, priority);

        // In a full integration, this would call:
        // tracking_manager.add_todo(TodoItem {
        //     summary,
        //     priority,
        //     status: "pending",
        //     created_at: Utc::now(),
        // }).await?

        let todo_id = format!("todo-{}", uuid::Uuid::new_v4());
        tracing::debug!("TODO added with ID: {}", todo_id);

        Ok(todo_id)
    }

    /// Get project summary from tracking
    pub fn get_summary(&self, project_id: &str) -> Result<ProjectSummary> {
        if !self.enabled {
            return Ok(ProjectSummary::default());
        }

        // Validate project ID
        if project_id.is_empty() {
            return Err(LifecycleError::integration(
                "Project ID cannot be empty".to_string(),
            ));
        }

        tracing::info!("Getting tracking summary for project: {}", project_id);

        // In a full integration, this would call:
        // tracking_manager.get_summary(project_id).await?

        // Return default summary with project context
        let summary = ProjectSummary {
            total_changes: 0,
            total_todos: 0,
            completed_todos: 0,
            velocity: 0.0,
            last_activity: None,
        };

        tracing::debug!(
            "Project summary retrieved: {} changes, {} todos",
            summary.total_changes,
            summary.total_todos
        );

        Ok(summary)
    }

    /// Sync Claude TODOs with tracking system
    pub fn sync_claude_todos(&self) -> Result<usize> {
        if !self.enabled || !self.sync_claude_todos {
            return Ok(0);
        }

        tracing::info!("Syncing Claude TODOs with tracking system");

        // In a full integration, this would:
        // 1. Scan .coder/ directory for task list files
        // 2. Parse todo entries using the TodoWrite format
        // 3. Extract task name, status (pending/in_progress/completed), and description
        // 4. Upload to tracking-manager
        // 5. Return count of synced items

        // For now, check if .coder directory exists
        let coder_path = std::path::PathBuf::from(".coder");
        if !coder_path.exists() {
            tracing::debug!("No .coder directory found, skipping Claude TODO sync");
            return Ok(0);
        }

        tracing::debug!("Found .coder directory, would scan for todo entries");

        // Count potential todo files
        let todo_count = std::fs::read_dir(&coder_path)
            .ok()
            .map(|entries| {
                let count = entries
                    .filter_map(|e| e.ok())
                    .filter(|e| {
                        e.path()
                            .file_name()
                            .and_then(|name| name.to_str())
                            .map(|s| s.contains("todo") || s.ends_with(".json"))
                            .unwrap_or(false)
                    })
                    .count();
                count
            })
            .unwrap_or(0);

        tracing::info!("Synced {} Claude TODO items", todo_count);

        Ok(todo_count)
    }
}

/// Project summary from tracking
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ProjectSummary {
    /// Total changes logged
    pub total_changes: usize,
    /// Total todos
    pub total_todos: usize,
    /// Completed todos
    pub completed_todos: usize,
    /// Current velocity (changes per week)
    pub velocity: f32,
    /// Last activity timestamp
    pub last_activity: Option<String>,
}

/// Integration manager coordinating all tool integrations
#[derive(Debug, Clone)]
pub struct IntegrationManager {
    /// Doc-lifecycle integration
    pub doc_lifecycle: DocLifecycleIntegration,
    /// Tracking integration
    pub tracking: TrackingManagerIntegration,
}

impl IntegrationManager {
    /// Create new integration manager
    pub fn new(
        doc_lifecycle: DocLifecycleIntegration,
        tracking: TrackingManagerIntegration,
    ) -> Self {
        Self {
            doc_lifecycle,
            tracking,
        }
    }

    /// Initialize all integrations for a phase
    pub fn initialize_for_phase(&self, phase: ProjectPhase) -> Result<()> {
        tracing::info!("Initializing integrations for phase: {}", phase);

        if self.doc_lifecycle.is_active_in_phase(phase) {
            tracing::debug!("Doc-lifecycle active in phase");
        }

        if self.tracking.is_active_in_phase(phase) {
            tracing::debug!("Tracking active in phase");
        }

        Ok(())
    }

    /// Get active integrations for phase
    pub fn active_integrations(&self, phase: ProjectPhase) -> Vec<String> {
        let mut active = vec![];

        if self.doc_lifecycle.is_active_in_phase(phase) {
            active.push("doc-lifecycle".to_string());
        }

        if self.tracking.is_active_in_phase(phase) {
            active.push("tracking".to_string());
        }

        active
    }

    /// Check all integrations health
    pub fn health_check(&self) -> HealthReport {
        HealthReport {
            doc_lifecycle_ok: self.doc_lifecycle.workspace_path.exists(),
            tracking_ok: self.tracking.workspace_path.exists(),
            timestamp: chrono::Utc::now(),
        }
    }
}

/// Health report for integrations
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthReport {
    /// Doc-lifecycle status
    pub doc_lifecycle_ok: bool,
    /// Tracking status
    pub tracking_ok: bool,
    /// Report timestamp
    pub timestamp: chrono::DateTime<chrono::Utc>,
}

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

    #[test]
    fn test_doc_lifecycle_integration_creation() {
        let integration = DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle"));
        assert!(!integration.enabled);
        assert!(integration.auto_update_root_files);
    }

    #[test]
    fn test_doc_lifecycle_phase_activation() {
        let integration =
            DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle")).enable();

        assert!(integration.is_active_in_phase(ProjectPhase::Devel));
        assert!(!integration.is_active_in_phase(ProjectPhase::Creation));
    }

    #[test]
    fn test_tracking_integration_creation() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        );

        assert!(!integration.enabled);
        assert!(integration.sync_claude_todos);
    }

    #[test]
    fn test_tracking_phase_activation() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        assert!(integration.is_active_in_phase(ProjectPhase::Devel));
        assert!(!integration.is_active_in_phase(ProjectPhase::Creation));
    }

    #[test]
    fn test_integration_manager_active_tools() {
        let doc_integration =
            DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle")).enable();
        let tracking_integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let manager = IntegrationManager::new(doc_integration, tracking_integration);

        let active = manager.active_integrations(ProjectPhase::Devel);
        assert_eq!(active.len(), 2);
        assert!(active.contains(&"doc-lifecycle".to_string()));
        assert!(active.contains(&"tracking".to_string()));
    }

    #[test]
    fn test_integration_manager_creation() {
        let doc_integration = DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle"));
        let tracking_integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        );

        let manager = IntegrationManager::new(doc_integration, tracking_integration);
        manager.initialize_for_phase(ProjectPhase::Devel).ok();
    }

    #[test]
    fn test_doc_lifecycle_trigger_classification_disabled() {
        let integration = DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle"));
        let result = integration.trigger_classification(&PathBuf::from("/some/path"));
        assert!(result.is_ok());
    }

    #[test]
    fn test_doc_lifecycle_trigger_classification_missing_path() {
        let integration =
            DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle")).enable();
        let result = integration.trigger_classification(&PathBuf::from("/nonexistent/path"));
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("does not exist"));
    }

    #[test]
    fn test_doc_lifecycle_trigger_consolidation() {
        let integration =
            DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle")).enable();
        let result = integration.trigger_consolidation();
        assert!(result.is_ok());
    }

    #[test]
    fn test_doc_lifecycle_update_root_files_disabled() {
        let integration = DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle"));
        let result = integration.update_root_files("# README", "# CHANGELOG");
        assert!(result.is_ok());
    }

    #[test]
    fn test_doc_lifecycle_update_root_files_empty_content() {
        let integration =
            DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle")).enable();

        let result = integration.update_root_files("", "# CHANGELOG");
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("cannot be empty"));
    }

    #[test]
    fn test_doc_lifecycle_update_root_files_success() {
        let integration =
            DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle")).enable();

        let result = integration.update_root_files("# Project README", "# CHANGELOG\n\n## v1.0.0");
        assert!(result.is_ok());
    }

    #[test]
    fn test_doc_lifecycle_generate_mdbook_disabled() {
        let integration = DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle"));
        let result = integration.generate_mdbook(&PathBuf::from("/docs"));
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "");
    }

    #[test]
    fn test_doc_lifecycle_generate_mdbook_auto_generate_disabled() {
        let integration =
            DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle")).enable();

        // Disable auto_generate_mdbook
        let mut integration = integration;
        integration.auto_generate_mdbook = false;

        let result = integration.generate_mdbook(&PathBuf::from("/docs"));
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "");
    }

    #[test]
    fn test_doc_lifecycle_generate_mdbook_missing_path() {
        let mut integration =
            DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle")).enable();
        integration.auto_generate_mdbook = true;

        let result = integration.generate_mdbook(&PathBuf::from("/nonexistent/docs"));
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("does not exist"));
    }

    #[test]
    fn test_tracking_log_change_disabled() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        );

        let result = integration.log_change("Fixed bug", "Critical", "bugfix");
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "");
    }

    #[test]
    fn test_tracking_log_change_enabled() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let result = integration.log_change("Implemented feature", "High", "feature");
        assert!(result.is_ok());
        let change_id = result.unwrap();
        assert!(change_id.starts_with("change-"));
    }

    #[test]
    fn test_tracking_log_change_empty_summary() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let result = integration.log_change("", "High", "feature");
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("cannot be empty"));
    }

    #[test]
    fn test_tracking_log_change_invalid_type() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        // Unknown change type generates warning but succeeds
        let result = integration.log_change("Fixed issue", "High", "unknown_type");
        assert!(result.is_ok());
    }

    #[test]
    fn test_tracking_add_todo_enabled() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let result = integration.add_todo("Complete documentation", "High");
        assert!(result.is_ok());
        let todo_id = result.unwrap();
        assert!(todo_id.starts_with("todo-"));
    }

    #[test]
    fn test_tracking_add_todo_empty_summary() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let result = integration.add_todo("", "High");
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("cannot be empty"));
    }

    #[test]
    fn test_tracking_add_todo_invalid_priority() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let result = integration.add_todo("Fix something", "InvalidPriority");
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("Invalid priority"));
    }

    #[test]
    fn test_tracking_add_todo_valid_priorities() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let priorities = ["Critical", "High", "Medium", "Low"];
        for priority in &priorities {
            let result = integration.add_todo("Sample task", priority);
            assert!(result.is_ok(), "Priority {} should be valid", priority);
        }
    }

    #[test]
    fn test_tracking_get_summary() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let result = integration.get_summary("project-123");
        assert!(result.is_ok());
        let summary = result.unwrap();
        assert_eq!(summary.total_changes, 0);
        assert_eq!(summary.total_todos, 0);
    }

    #[test]
    fn test_tracking_get_summary_empty_project_id() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let result = integration.get_summary("");
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("cannot be empty"));
    }

    #[test]
    fn test_tracking_sync_todos_disabled() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        );

        let result = integration.sync_claude_todos();
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 0);
    }

    #[test]
    fn test_tracking_sync_todos_enabled() {
        let integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        )
        .enable();

        let result = integration.sync_claude_todos();
        assert!(result.is_ok());
        // No todos synced yet
        assert_eq!(result.unwrap(), 0);
    }

    #[test]
    fn test_integration_manager_health_check() {
        let doc_integration = DocLifecycleIntegration::new(PathBuf::from("/tools/doc-lifecycle"));
        let tracking_integration = TrackingManagerIntegration::new(
            PathBuf::from("/tools/tracking"),
            PathBuf::from(".vapora/tracking.db"),
        );

        let manager = IntegrationManager::new(doc_integration, tracking_integration);
        let report = manager.health_check();

        // Both paths don't exist
        assert!(!report.doc_lifecycle_ok);
        assert!(!report.tracking_ok);
    }
}
