use std::env;
use std::fs;
use std::path::PathBuf;

use serde::{Deserialize, Serialize};

const DEFAULT_BASE_URL: &str = "https://biolib.com";

#[derive(Debug, Clone)]
pub struct Config {
    pub base_url: String,
    pub api_token: Option<String>,
    pub ca_bundle: Option<String>,
    pub is_public_biolib: bool,
    pub cloud_base_url: Option<String>,
    pub cloud_job_storage_base_url: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Default)]
pub struct UserState {
    pub refresh_token: Option<String>,
}

impl Config {
    pub fn load() -> Self {
        let base_url = env::var("BIOLIB_BASE_URL").unwrap_or_else(|_| DEFAULT_BASE_URL.to_string());

        let api_token = env::var("BIOLIB_TOKEN").ok();

        let ca_bundle = env::var("BIOLIB_CA_BUNDLE")
            .ok()
            .or_else(|| env::var("REQUESTS_CA_BUNDLE").ok())
            .or_else(|| env::var("SSL_CERT_FILE").ok());

        let is_public_biolib = base_url.ends_with("biolib.com")
            || env::var("BIOLIB_ENVIRONMENT_IS_PUBLIC_BIOLIB")
                .map(|v| v.eq_ignore_ascii_case("true"))
                .unwrap_or(false);

        let cloud_base_url = env::var("BIOLIB_CLOUD_BASE_URL")
            .ok()
            .filter(|v| !v.is_empty());
        let cloud_job_storage_base_url = env::var("BIOLIB_CLOUD_JOB_STORAGE_BASE_URL")
            .ok()
            .filter(|v| !v.is_empty());

        Self {
            base_url,
            api_token,
            ca_bundle,
            is_public_biolib,
            cloud_base_url,
            cloud_job_storage_base_url,
        }
    }

    pub fn state_file_path() -> PathBuf {
        let home = env::var("HOME")
            .map(PathBuf::from)
            .unwrap_or_else(|_| PathBuf::from("."));
        home.join(".biolib").join("state.json")
    }

    pub fn load_user_state() -> UserState {
        let path = Self::state_file_path();
        if path.exists() {
            if let Ok(content) = fs::read_to_string(&path) {
                if let Ok(state) = serde_json::from_str(&content) {
                    return state;
                }
            }
        }
        UserState::default()
    }

    pub fn save_user_state(state: &UserState) -> crate::Result<()> {
        let path = Self::state_file_path();
        if let Some(parent) = path.parent() {
            fs::create_dir_all(parent)?;
        }
        let content = serde_json::to_string_pretty(state)?;
        fs::write(path, content)?;
        Ok(())
    }
}
