use base64::{engine::general_purpose::STANDARD, Engine as _};
use ed25519_dalek::{Signer, SigningKey};
use serde::{Deserialize, Serialize};
use std::env;
use std::fs;
use std::path::PathBuf;

#[derive(Serialize, Deserialize)]
struct LicensePayload {
  product_id: String,
  license_key: String,
  hwid: String,
}

fn generate_random_bytes(buf: &mut [u8]) -> Result<(), String> {
  getrandom::getrandom(buf).map_err(|e| format!("Failed to generate secure random bytes: {}", e))
}

fn find_workspace_root() -> PathBuf {
  let mut dir = env::current_dir().unwrap_or_else(|_| PathBuf::from("."));

  loop {
    if dir.join("licensing_profiles.json").exists() || dir.join("src-tauri").exists() {
      return dir;
    }
    if let Some(parent) = dir.parent() {
      dir = parent.to_path_buf();
    } else {
      break;
    }
  }

  env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
}

fn main() {
  let args: Vec<String> = env::args().collect();

  if args.len() < 2 {
    print_usage();
    return;
  }

  match args[1].as_str() {
    "generate-keys" => {
      let profile_name = if args.len() > 2 { &args[2] } else { "key" };

      let workspace_root = find_workspace_root();
      let default_output_dir = workspace_root.join("licensing");

      let output_dir_path = if args.len() > 3 {
        PathBuf::from(&args[3])
      } else {
        default_output_dir
      };

      let mut key_bytes = [0u8; 32];

      if let Err(e) = generate_random_bytes(&mut key_bytes) {
        println!("Failed to generate secure random bytes: {}", e);
        return;
      }

      let signing_key = SigningKey::from_bytes(&key_bytes);
      let verifying_key = signing_key.verifying_key();

      let priv_hex = key_bytes
        .iter()
        .map(|b| format!("{:02x}", b))
        .collect::<String>();
      let pub_hex = verifying_key
        .to_bytes()
        .iter()
        .map(|b| format!("{:02x}", b))
        .collect::<String>();

      println!("Generated Keypair for Profile: {}", profile_name);
      println!("Private Key (HEX): {}", priv_hex);
      println!("Public Key (HEX):  {}", pub_hex);
      println!("Public Key (Rust Bytes): {:?}", verifying_key.to_bytes());

      if let Err(e) = fs::create_dir_all(&output_dir_path) {
        println!(
          "Failed to create output directory {}: {}",
          output_dir_path.display(),
          e
        );
        return;
      }

      let priv_file = output_dir_path.join(format!("{}.priv", profile_name));
      let pub_file = output_dir_path.join(format!("{}.pub", profile_name));

      if let Err(e) = fs::write(&priv_file, &priv_hex) {
        println!(
          "Failed to write private key to {}: {}",
          priv_file.display(),
          e
        );
        return;
      }

      if let Err(e) = fs::write(&pub_file, &pub_hex) {
        println!(
          "Failed to write public key to {}: {}",
          pub_file.display(),
          e
        );
        return;
      }

      println!(
        "Successfully persisted keys under: {}",
        output_dir_path.display()
      );
    }
    "issue" => {
      if args.len() < 4 {
        println!("Usage: license-tool issue <private-key-hex> <hwid> [product_id] [license_key]");
        return;
      }

      let priv_key_hex = &args[2];
      let hwid = &args[3];
      let product_id = if args.len() > 4 {
        &args[4]
      } else {
        "cleancopy"
      };

      let license_key = if args.len() > 5 {
        &args[5]
      } else {
        "manual_activation"
      };

      let mut priv_key_bytes = Vec::new();
      let mut chars = priv_key_hex.chars().peekable();

      while chars.peek().is_some() {
        let chunk: String = chars.by_ref().take(2).collect();

        if let Ok(byte) = u8::from_str_radix(&chunk, 16) {
          priv_key_bytes.push(byte);
        } else {
          println!("Invalid hex character in private key");
          return;
        }
      }

      let priv_key_arr: [u8; 32] = match priv_key_bytes.try_into() {
        Ok(arr) => arr,
        Err(_) => {
          println!("Private key must be exactly 32 bytes (64 hex characters)");
          return;
        }
      };

      let signing_key = SigningKey::from_bytes(&priv_key_arr);

      let payload = LicensePayload {
        product_id: product_id.to_string(),
        license_key: license_key.to_string(),
        hwid: hwid.to_string(),
      };

      let payload_str = serde_json::to_string(&payload).unwrap();
      let payload_b64 = STANDARD.encode(payload_str.as_bytes());

      let signature = signing_key.sign(payload_b64.as_bytes());
      let signature_b64 = STANDARD.encode(signature.to_bytes());

      println!("LICENSE KEY:\n{}.{}", payload_b64, signature_b64);
    }
    "deactivate" => {
      let appdata = env::var("APPDATA").unwrap_or_else(|_| "".to_string());

      if appdata.is_empty() {
        println!("Error: APPDATA environment variable not found.");
        return;
      }

      let mut path = PathBuf::from(appdata);
      path.push("com.cleancopy.app");
      path.push("license.lic");

      if path.exists() {
        match fs::remove_file(&path) {
          Ok(_) => println!(
            "Successfully deactivated license. Deleted: {}",
            path.display()
          ),
          Err(e) => println!("Error deleting license file: {}", e),
        }
      } else {
        println!(
          "No active license found to deactivate at: {}",
          path.display()
        );
      }
    }
    _ => print_usage(),
  }
}

fn print_usage() {
  println!("CleanCopy License Tool");
  println!("Usage:");
  println!("  license-tool generate-keys [profile_name] [output_dir]");
  println!("  license-tool issue <private-key-hex> <hwid> [product_id] [license_key]");
  println!("  license-tool deactivate");
}
