use serde::{Deserialize, Serialize};
use tauri::Manager;
use url::Url;

const MAX_LABEL_LEN: usize = 80;
const MAX_ISSUER_LEN: usize = 80;
const MIN_TOTP_SECRET_LEN: usize = 16;
const MAX_TOTP_SECRET_LEN: usize = 256;

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct ValidationResult {
    ok: bool,
    value: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct TotpProfileInput {
    issuer: String,
    label: String,
    secret: String,
    digits: Option<u8>,
    period: Option<u16>,
}

#[tauri::command]
fn validate_qr_session_payload(payload: String) -> Result<ValidationResult, String> {
    let trimmed = payload.trim();
    if trimmed.is_empty() {
        return Err("QR-код пустой".into());
    }

    let session_id = match Url::parse(trimmed) {
        Ok(url) => url
            .query_pairs()
            .find(|(key, _)| key == "sessionId" || key == "session_id")
            .map(|(_, value)| value.to_string())
            .or_else(|| {
                url.path_segments()
                    .and_then(|segments| segments.last().map(ToString::to_string))
            })
            .unwrap_or_default(),
        Err(_) => trimmed.to_string(),
    };

    validate_uuid_like(&session_id)?;
    Ok(ValidationResult {
        ok: true,
        value: session_id,
    })
}

#[tauri::command]
fn validate_api_base_url(url: String) -> Result<ValidationResult, String> {
    let parsed = Url::parse(url.trim()).map_err(|_| "Некорректный URL API".to_string())?;
    match parsed.scheme() {
        "http" | "https" => Ok(ValidationResult {
            ok: true,
            value: parsed.as_str().trim_end_matches('/').to_string(),
        }),
        _ => Err("URL API должен начинаться с http:// или https://".into()),
    }
}

#[tauri::command]
fn validate_totp_profile_input(input: TotpProfileInput) -> Result<ValidationResult, String> {
    let issuer = input.issuer.trim();
    let label = input.label.trim();
    let secret = normalize_base32_secret(&input.secret);
    let digits = input.digits.unwrap_or(6);
    let period = input.period.unwrap_or(30);

    if issuer.is_empty() || issuer.len() > MAX_ISSUER_LEN {
        return Err("Название сервиса должно содержать от 1 до 80 символов".into());
    }
    if label.is_empty() || label.len() > MAX_LABEL_LEN {
        return Err("Название аккаунта должно содержать от 1 до 80 символов".into());
    }
    if secret.len() < MIN_TOTP_SECRET_LEN || secret.len() > MAX_TOTP_SECRET_LEN {
        return Err("TOTP secret должен содержать от 16 до 256 символов base32".into());
    }
    if !secret.chars().all(|ch| matches!(ch, 'A'..='Z' | '2'..='7' | '=')) {
        return Err("TOTP secret должен быть в формате base32".into());
    }
    if digits != 6 && digits != 8 {
        return Err("TOTP поддерживает только 6 или 8 цифр".into());
    }
    if !(15..=120).contains(&period) {
        return Err("Период TOTP должен быть от 15 до 120 секунд".into());
    }

    Ok(ValidationResult {
        ok: true,
        value: secret,
    })
}

fn validate_uuid_like(value: &str) -> Result<(), String> {
    let normalized = value.trim();
    if normalized.len() != 36 {
        return Err("QR-код не содержит корректный UUID сессии".into());
    }
    for (index, ch) in normalized.chars().enumerate() {
        let dash = matches!(index, 8 | 13 | 18 | 23);
        if dash && ch != '-' {
            return Err("QR-код не содержит корректный UUID сессии".into());
        }
        if !dash && !ch.is_ascii_hexdigit() {
            return Err("QR-код не содержит корректный UUID сессии".into());
        }
    }
    Ok(())
}

fn normalize_base32_secret(secret: &str) -> String {
    secret
        .trim()
        .chars()
        .filter(|ch| !ch.is_whitespace() && *ch != '-')
        .map(|ch| ch.to_ascii_uppercase())
        .collect()
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .plugin(tauri_plugin_stronghold::Builder::new(|password| password.as_bytes().to_vec()).build())
        .invoke_handler(tauri::generate_handler![
            validate_qr_session_payload,
            validate_api_base_url,
            validate_totp_profile_input
        ])
        .setup(|app| {
            let _ = app.path().app_data_dir().map(std::fs::create_dir_all);
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("ошибка запуска Lendry ID Super App");
}
