use crate::plugins::error::PluginError;
use r2x_config::Config;
use r2x_manifest::package_discovery::PackageLocator;
use r2x_manifest::types::Manifest;
use r2x_python::utils::resolve_site_package_path;
use std::path::PathBuf;

pub struct PluginContext {
    pub config: Config,
    pub manifest: Manifest,
    pub uv_path: String,
    pub venv_path: String,
    pub python_path: String,
    pub locator: PackageLocator,
}

impl PluginContext {
    pub fn load() -> Result<Self, PluginError> {
        let mut config = Config::load()
            .map_err(|e| PluginError::Config(format!("Failed to load config: {e}")))?;

        config
            .ensure_uv_path()
            .map_err(|e| PluginError::Config(format!("Failed to setup uv: {e}")))?;
        config
            .ensure_cache_path()
            .map_err(|e| PluginError::Config(format!("Failed to setup cache: {e}")))?;
        config
            .ensure_venv_path()
            .map_err(|e| PluginError::Config(format!("Failed to setup venv: {e}")))?;

        let uv_path = config
            .uv_path
            .clone()
            .ok_or_else(|| PluginError::Config("uv path not configured".to_string()))?;

        let venv_path = config.get_venv_path();
        let python_path = config.get_venv_python_path();

        let site_packages = resolve_site_package_path(&PathBuf::from(&venv_path))
            .map_err(|e| PluginError::Python(format!("Failed to resolve site-packages: {e}")))?;

        let uv_cache_dir = resolve_uv_cache_dir();
        let locator = PackageLocator::new(site_packages, uv_cache_dir).map_err(|e| {
            PluginError::Locator(format!("Failed to initialize package locator: {e}"))
        })?;

        let manifest = Manifest::load()?;

        Ok(PluginContext {
            config,
            manifest,
            uv_path,
            venv_path,
            python_path,
            locator,
        })
    }

    pub fn refresh_locator(&mut self) -> Result<(), PluginError> {
        self.locator
            .refresh()
            .map_err(|e| PluginError::Locator(format!("Failed to refresh package locator: {e}")))
    }
}

fn resolve_uv_cache_dir() -> Option<PathBuf> {
    let base = std::env::var_os("UV_CACHE_DIR")
        .map(PathBuf::from)
        .or_else(|| dirs::cache_dir().map(|cache| cache.join("uv")));
    base.map(|root| root.join("archive-v0"))
        .filter(|path| path.exists())
}
