use std::fs;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{error, info, warn};

/// Manages the ai.md self-improvement file.
/// Loaded on startup and periodically refreshed.
pub struct InstructionsManager {
    path: PathBuf,
    current: RwLock<String>,
}

impl InstructionsManager {
    pub fn new(path: PathBuf) -> Self {
        let initial = fs::read_to_string(&path).unwrap_or_default();
        if initial.is_empty() {
            warn!("ai.md is empty or missing at {:?}", path);
        } else {
            info!("Loaded ai.md ({} bytes)", initial.len());
        }
        Self {
            path,
            current: RwLock::new(initial),
        }
    }

    /// Read the current instructions
    pub async fn get(&self) -> String {
        self.current.read().await.clone()
    }

    /// Append a new entry to the Improvement Log and optionally update the instructions.
    /// Returns the updated full content.
    pub async fn update(&self, entry: &str, new_content: Option<&str>) -> Result<String, String> {
        if let Some(content) = new_content {
            // Full replacement
            fs::write(&self.path, content).map_err(|e| format!("Write failed: {}", e))?;
            let mut current = self.current.write().await;
            *current = content.to_string();
            info!("ai.md fully replaced ({} bytes)", content.len());
            Ok(content.to_string())
        } else {
            // Append to Improvement Log only
            let mut current = self.current.write().await;
            let log_entry = format!("\n- {} — {}", chrono::Utc::now().format("%Y-%m-%d %H:%M"), entry);
            // Find the Improvement Log section and append
            if let Some(pos) = current.rfind("\n## Improvement Log") {
                // Find the next section after Improvement Log, or end of file
                let after_log = &current[pos..];
                if let Some(section_start) = after_log[1..].find("\n## ") {
                    let insert_at = pos + 1 + section_start;
                    current.insert_str(insert_at, &format!("{}\n", log_entry));
                } else {
                    current.push_str(&format!("{}\n", log_entry));
                }
            } else {
                current.push_str(&format!("\n## Improvement Log\n{}", log_entry));
            }
            fs::write(&self.path, &*current).map_err(|e| format!("Write failed: {}", e))?;
            info!("ai.md improvement log appended: {}", entry);
            Ok(current.clone())
        }
    }

    /// Reload from disk
    pub async fn reload(&self) {
        match fs::read_to_string(&self.path) {
            Ok(content) => {
                let len = content.len();
                let mut current = self.current.write().await;
                *current = content;
                info!("ai.md reloaded from disk ({} bytes)", len);
            }
            Err(e) => error!("Failed to reload ai.md: {}", e),
        }
    }
}

/// Wrapper for thread-safe sharing
pub type SharedInstructions = Arc<InstructionsManager>;

pub fn create_shared(path: PathBuf) -> SharedInstructions {
    Arc::new(InstructionsManager::new(path))
}
