//! State management for idempotent operations
//!
//! Tracks what has been configured to avoid redundant operations.

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};

const STATE_FILE: &str = ".sea-forge-state.json";

/// Tracks the state of configured components
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct ForgeState {
    /// Version of the state file format
    pub version: u32,
    /// Fingerprints of configured components
    pub components: HashMap<String, ComponentState>,
    /// Last successful run timestamp
    pub last_run: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentState {
    /// SHA256 hash of the configuration
    pub fingerprint: String,
    /// When this component was last configured
    pub configured_at: String,
    /// Current status
    pub status: ComponentStatus,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ComponentStatus {
    Configured,
    Running,
    Stopped,
    Failed,
    Unknown,
}

impl ForgeState {
    /// Load state from project root
    pub fn load(project_root: &Path) -> Result<Self> {
        let state_path = project_root.join(STATE_FILE);
        if state_path.exists() {
            let content = fs::read_to_string(&state_path).context("Failed to read state file")?;
            serde_json::from_str(&content).context("Failed to parse state file")
        } else {
            Ok(Self::default())
        }
    }

    /// Save state to project root
    pub fn save(&self, project_root: &Path) -> Result<()> {
        let state_path = project_root.join(STATE_FILE);
        let content = serde_json::to_string_pretty(self).context("Failed to serialize state")?;
        fs::write(&state_path, content).context("Failed to write state file")?;
        Ok(())
    }

    /// Update component state
    pub fn set_component(&mut self, component: &str, fingerprint: &str, status: ComponentStatus) {
        self.components.insert(
            component.to_string(),
            ComponentState {
                fingerprint: fingerprint.to_string(),
                configured_at: chrono::Utc::now().to_rfc3339(),
                status,
            },
        );
    }
}

/// Get project root by looking for justfile
pub fn find_project_root() -> Result<PathBuf> {
    let current = std::env::current_dir()?;
    let mut path = current.as_path();

    loop {
        if path.join("justfile").exists() && path.join("Cargo.toml").exists() {
            return Ok(path.to_path_buf());
        }
        path = path.parent().context("Could not find SEA project root")?;
    }
}
