use shared::licensing::{
  get_activation_url, get_all_valid_key_bytes, set_license_active, verify_license_with_any_key,
};
use std::fs;
use std::path::PathBuf;
use std::sync::OnceLock;
use tauri::Manager;
use winreg::enums::*;
use winreg::RegKey;

static HWID_CACHE: OnceLock<String> = OnceLock::new();

pub fn get_hwid(app: &tauri::AppHandle) -> String {
  if let Some(cached) = HWID_CACHE.get() {
    return cached.clone();
  }

  let mut combined = String::new();

  #[cfg(target_os = "windows")]
  {
    if let Ok(hklm) =
      RegKey::predef(HKEY_LOCAL_MACHINE).open_subkey("SOFTWARE\\Microsoft\\Cryptography")
    {
      if let Ok(guid) = hklm.get_value::<String, _>("MachineGuid") {
        combined.push_str(&guid);
      }
    }

    if let Ok(hklm) =
      RegKey::predef(HKEY_LOCAL_MACHINE).open_subkey("HARDWARE\\DESCRIPTION\\System\\BIOS")
    {
      if let Ok(serial) = hklm.get_value::<String, _>("BaseBoardSerialNumber") {
        combined.push_str(&serial);
      }
    }
  }

  if combined.is_empty() {
    combined = load_or_create_fallback_hwid(app);
  }

  use sha2::{Digest, Sha256};
  let mut hasher = Sha256::new();

  hasher.update(combined.as_bytes());

  let result = hasher.finalize();
  let hwid = result
    .iter()
    .map(|b| format!("{:02x}", b))
    .collect::<String>();

  let _ = HWID_CACHE.set(hwid.clone());

  hwid
}

fn load_or_create_fallback_hwid(app: &tauri::AppHandle) -> String {
  let mut path = app
    .path()
    .app_config_dir()
    .unwrap_or_else(|_| std::env::current_dir().unwrap());

  let _ = fs::create_dir_all(&path);

  path.push("fallback_hwid");

  if let Ok(existing) = fs::read_to_string(&path) {
    let trimmed = existing.trim().to_string();

    if !trimmed.is_empty() {
      return trimmed;
    }
  }

  let mut buf = [0u8; 16];

  getrandom::getrandom(&mut buf).expect("Failed to generate random bytes for fallback HWID");

  let uuid = format!(
        "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
        buf[0], buf[1], buf[2], buf[3],
        buf[4], buf[5],
        buf[6], buf[7],
        buf[8], buf[9],
        buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]
    );

  let _ = fs::write(&path, &uuid);

  uuid
}

pub fn get_license_path(app: &tauri::AppHandle) -> PathBuf {
  let mut path = app
    .path()
    .app_config_dir()
    .unwrap_or_else(|_| std::env::current_dir().unwrap());

  let _ = fs::create_dir_all(&path);

  path.push("license.lic");

  path
}

pub fn check_active_license(app: &tauri::AppHandle) -> bool {
  if shared::licensing::is_license_active() {
    return true;
  }

  let path = get_license_path(app);

  if path.exists() {
    match fs::read_to_string(&path) {
      Ok(token) => {
        let hwid = get_hwid(app);
        match verify_license_with_any_key(&token, &get_all_valid_key_bytes(), &hwid) {
          Ok(_) => {
            log::info!("Local license validation succeeded for HWID: {}", hwid);
            set_license_active(true);
            return true;
          }
          Err(e) => {
            log::warn!(
              "Local license validation failed: {}. Path: {}",
              e,
              path.display()
            );
          }
        }
      }
      Err(e) => {
        log::error!("Failed to read license file from {}: {}", path.display(), e);
      }
    }
  } else {
    log::info!(
      "No license file found at {}. App is unregistered.",
      path.display()
    );
  }

  false
}

pub fn activate_license(app: &tauri::AppHandle, license_key: &str) -> Result<(), String> {
  let hwid = get_hwid(app);
  let url = get_activation_url();

  log::info!("Initiating license activation. URL: '{}'", url);

  let payload = serde_json::json!({
      "product_id": "cleancopy",
      "license_key": license_key.trim(),
      "hwid": hwid
  });

  let response_result = ureq::AgentBuilder::new()
    .timeout(std::time::Duration::from_secs(10))
    .build()
    .post(url)
    .set("Accept", "application/json")
    .set("Content-Type", "application/json")
    .send_json(payload);

  let response = match response_result {
    Ok(res) => res,
    Err(ureq::Error::Status(code, res)) => {
      log::warn!("Activation server returned status code: {}", code);
      res
    }
    Err(e) => {
      let err_msg = format!("Network request failed: {}", e);
      log::error!("{}", err_msg);
      return Err(err_msg);
    }
  };

  #[derive(serde::Deserialize)]
  struct ActivationResponse {
    license_token: Option<String>,
    error: Option<String>,
  }

  let res_data: ActivationResponse = response.into_json().map_err(|e| {
    let err_msg = format!("Failed to parse response JSON: {}", e);
    log::error!("{}", err_msg);
    err_msg
  })?;

  if let Some(err) = res_data.error {
    log::warn!("Activation server rejected license: {}", err);
    return Err(err);
  }

  let token = res_data.license_token.ok_or_else(|| {
    let err_msg = "No license token returned from server".to_string();
    log::error!("{}", err_msg);
    err_msg
  })?;

  verify_license_with_any_key(&token, &get_all_valid_key_bytes(), &hwid).map_err(|e| {
    let err_msg = format!("Retrieved token signature verification failed: {}", e);
    log::error!("{}", err_msg);
    err_msg
  })?;

  let path = get_license_path(app);

  fs::write(&path, token.trim()).map_err(|e| {
    let err_msg = format!("Failed to save license token to {}: {}", path.display(), e);
    log::error!("{}", err_msg);
    err_msg
  })?;

  log::info!(
    "Successfully activated license. Token saved to {}",
    path.display()
  );
  set_license_active(true);
  Ok(())
}

#[tauri::command]
pub fn get_hwid_command(app: tauri::AppHandle) -> String {
  get_hwid(&app)
}

#[tauri::command]
pub fn activate_license_command(app: tauri::AppHandle, license_key: String) -> Result<(), String> {
  log::info!("activate_license_command invoked from frontend UI");
  activate_license(&app, &license_key)
}

#[tauri::command]
pub fn verify_and_save_offline_token(app: tauri::AppHandle, token: String) -> Result<(), String> {
  log::info!("verify_and_save_offline_token invoked from frontend UI");

  let hwid = get_hwid(&app);
  let keys = get_all_valid_key_bytes();

  verify_license_with_any_key(&token, &keys, &hwid).map_err(|e| {
    let err_msg = format!("Offline token verification failed: {}", e);
    log::error!("{}", err_msg);
    err_msg
  })?;

  let path = get_license_path(&app);

  fs::write(&path, token.trim()).map_err(|e| {
    let err_msg = format!("Failed to save offline token to {}: {}", path.display(), e);
    log::error!("{}", err_msg);
    err_msg
  })?;

  log::info!("Successfully saved offline token to {}", path.display());
  set_license_active(true);
  Ok(())
}

#[tauri::command]
pub fn is_license_active_command(app: tauri::AppHandle) -> bool {
  check_active_license(&app)
}
