use crate::repository::api::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize)]
pub struct MergeResult {
    pub operation: String,
    pub table_name: String,
    pub rows_affected: i64,
    pub details: String,
}

/// Authenticate user with email/username and password to get user ID
pub async fn authenticate_user(email_or_username: &str, password: &str) -> Result<String> {
    let url = format!("{}/rpc/signin", *BACKEND_API_URL);
    log::trace!("authenticating user: {}", email_or_username);

    #[derive(Serialize)]
    struct SigninRequest {
        username: String,
        password: String,
    }

    let request = SigninRequest {
        username: email_or_username.to_string(),
        password: password.to_string(),
    };

    let response = reqwest::Client::new()
        .post(&url)
        .header("Content-Type", "application/json")
        .header("Accept", "text/plain")
        .json(&request)
        .send()
        .await?;

    if !response.status().is_success() {
        let error_text = response.text().await?;
        return Err(Report::msg(format!(
            "Authentication failed: {}",
            prettify_json_or_text(&error_text)
        )));
    }

    let token = response.text().await?;
    
    // Decode JWT token to get user ID
    // The token contains user_id in the 'sub' field
    let user_id = decode_jwt_sub(&token)?;
    
    Ok(user_id)
}

/// Merge two user accounts using the database function
pub async fn merge_users(source_user_id: &str, target_user_id: &str) -> Result<Vec<MergeResult>> {
    let url = format!("{}/rpc/merge_users", *BACKEND_API_URL);
    log::trace!("merging users: {} -> {}", source_user_id, target_user_id);

    #[derive(Serialize)]
    struct MergeRequest {
        source_user_id: String,
        target_user_id: String,
        dry_run: bool,
    }

    let request = MergeRequest {
        source_user_id: source_user_id.to_string(),
        target_user_id: target_user_id.to_string(),
        dry_run: false,
    };

    let auth_token = get_auth_token().await?;

    let response = reqwest::Client::new()
        .post(&url)
        .header("Authorization", auth_token)
        .header("Content-Type", "application/json")
        .header("Content-Profile", "vgate")
        .json(&request)
        .send()
        .await?;

    if !response.status().is_success() {
        let error_text = response.text().await?;
        return Err(Report::msg(format!(
            "Failed to merge users: {}",
            prettify_json_or_text(&error_text)
        )));
    }

    let results: Vec<MergeResult> = response.json().await?;
    Ok(results)
}

/// Decode JWT token to extract the 'sub' field (user ID)
fn decode_jwt_sub(token: &str) -> Result<String> {
    // Simple JWT decoding - in production you might want to use a proper JWT library
    // JWT format: header.payload.signature
    let parts: Vec<&str> = token.split('.').collect();
    if parts.len() != 3 {
        return Err(Report::msg("Invalid JWT token format"));
    }

    // Decode the payload (base64url)
    let payload = parts[1];
    let decoded = base64_url_decode(payload)?;
    
    // Parse JSON to get the 'sub' field
    let json: serde_json::Value = serde_json::from_str(&decoded)?;
    let user_id = json["sub"]
        .as_str()
        .ok_or_else(|| Report::msg("No 'sub' field in JWT token"))?;
    
    Ok(user_id.to_string())
}

/// Base64 URL decode
fn base64_url_decode(input: &str) -> Result<String> {
    // Add padding if needed
    let mut input = input.to_string();
    while input.len() % 4 != 0 {
        input.push('=');
    }
    
    // Replace URL-safe characters
    let input = input.replace('-', "+").replace('_', "/");
    
    use base64::{Engine as _, engine::general_purpose};
    let decoded = general_purpose::STANDARD.decode(input)
        .map_err(|e| Report::msg(format!("Base64 decode error: {}", e)))?;
    
    String::from_utf8(decoded)
        .map_err(|e| Report::msg(format!("UTF-8 decode error: {}", e)))
}
