use std::collections::HashMap;
use std::sync::RwLock;
use url::Url;

use crate::server::{AccessToken, AuthorizationCode};

/// Server state containing all in-memory storage for the IndieAuth server
pub struct AppState {
    /// Signing key for JWT tokens (32 bytes)
    pub signing_key: [u8; 32],

    /// Server issuer URL (e.g., http://127.0.0.1:8080)
    pub issuer: Url,

    /// Active authorization codes (code -> code data)
    pub codes: RwLock<HashMap<String, AuthorizationCode>>,

    /// Active access tokens (token -> token data)
    pub tokens: RwLock<HashMap<String, AccessToken>>,

    /// Demo users database
    pub users: HashMap<String, User>,
}

/// User account information
#[derive(Clone)]
pub struct User {
    pub password: String,
    pub profile: Profile,
}

/// User profile information that can be returned via scopes
#[derive(Clone)]
pub struct Profile {
    /// The identity URL (can be external or local)
    pub me: Url,
    /// Display name
    pub name: String,
    /// Profile image URL (optional)
    pub photo: Option<Url>,
    /// Email address (optional)
    pub email: Option<String>,
    /// User's main website URL (optional, may differ from me)
    pub url: Option<Url>,
}

impl AppState {
    /// Create a new AppState with the given signing key and issuer URL
    pub fn new(signing_key: [u8; 32], issuer: Url) -> Self {
        let users = Self::create_demo_users(&issuer);

        Self {
            signing_key,
            issuer,
            codes: RwLock::new(HashMap::new()),
            tokens: RwLock::new(HashMap::new()),
            users,
        }
    }

    /// Create demo users with different profile configurations
    fn create_demo_users(issuer: &Url) -> HashMap<String, User> {
        let mut users = HashMap::new();

        // User 1: Alice - Basic profile (name only)
        users.insert(
            "alice".to_string(),
            User {
                password: "alice".to_string(),
                profile: Profile {
                    me: issuer.join("user/alice").unwrap(),
                    name: "Alice".to_string(),
                    photo: None,
                    email: None,
                    url: None,
                },
            },
        );

        // User 2: Bob - Full profile with avatar image
        users.insert(
            "bob".to_string(),
            User {
                password: "bob".to_string(),
                profile: Profile {
                    me: issuer.join("user/bob").unwrap(),
                    name: "Bob Builder".to_string(),
                    photo: Some(
                        format!("https://api.dicebear.com/7.x/avataaars/svg?seed=bob")
                            .parse()
                            .unwrap(),
                    ),
                    email: Some("bob@example.com".to_string()),
                    url: None,
                },
            },
        );

        // User 3: Charlie - External URL profile with identicon
        users.insert(
            "charlie".to_string(),
            User {
                password: "charlie".to_string(),
                profile: Profile {
                    me: "https://charlie.example.com/".parse().unwrap(), // External identity!
                    name: "Charlie Web".to_string(),
                    photo: Some(
                        format!("https://api.dicebear.com/7.x/identicon/svg?seed=charlie")
                            .parse()
                            .unwrap(),
                    ),
                    email: Some("charlie@charlie.example.com".to_string()),
                    url: Some("https://charlie.example.com/".parse().unwrap()),
                },
            },
        );

        // User 4: Demo - Simple profile with bot avatar
        users.insert(
            "demo".to_string(),
            User {
                password: "demo".to_string(),
                profile: Profile {
                    me: issuer.join("user/demo").unwrap(),
                    name: "Demo User".to_string(),
                    photo: Some(
                        format!("https://api.dicebear.com/7.x/bottts/svg?seed=demo")
                            .parse()
                            .unwrap(),
                    ),
                    email: Some("demo@example.com".to_string()),
                    url: None,
                },
            },
        );

        users
    }

    /// Validate user credentials
    pub fn validate_user(&self, username: &str, password: &str) -> Option<&User> {
        self.users
            .get(username)
            .filter(|user| user.password == password)
    }

    /// Store an authorization code
    pub fn store_code(&self, code: String, code_data: AuthorizationCode) {
        self.codes.write().unwrap().insert(code, code_data);
    }

    /// Retrieve and consume an authorization code (removes it from storage)
    pub fn consume_code(&self, code: &str) -> Option<AuthorizationCode> {
        self.codes.write().unwrap().remove(code)
    }

    /// Store an access token
    pub fn store_token(&self, token: String, token_data: AccessToken) {
        self.tokens.write().unwrap().insert(token, token_data);
    }

    /// Retrieve an access token (does not consume it)
    pub fn get_token(&self, token: &str) -> Option<AccessToken> {
        self.tokens.read().unwrap().get(token).cloned()
    }
}
