from __future__ import annotations

import subprocess
import platform
import shutil
from pathlib import Path
from rich import print
import typer


def detect_mkcert() -> str | None:
	"""Check if mkcert is installed and return its path."""
	return shutil.which("mkcert")


def install_mkcert() -> bool:
	"""
	Install mkcert based on the operating system.
	Returns True if successful, False otherwise.
	"""
	system = platform.system().lower()
	
	print(f"[cyan]→ Detected OS: {system}[/]")
	
	try:
		if system == "darwin":  # macOS
			print("[cyan]→ Installing mkcert via Homebrew...[/]")
			subprocess.run(["brew", "install", "mkcert"], check=True)
			subprocess.run(["brew", "install", "nss"], check=True)  # For Firefox support
			
		elif system == "linux":
			# Try to detect Linux distribution
			try:
				with open("/etc/os-release") as f:
					os_release = f.read().lower()
			except FileNotFoundError:
				os_release = ""
			
			if "ubuntu" in os_release or "debian" in os_release:
				print("[cyan]→ Installing mkcert via apt...[/]")
				subprocess.run(["sudo", "apt", "update"], check=True)
				subprocess.run(["sudo", "apt", "install", "-y", "libnss3-tools"], check=True)
				subprocess.run([
					"sudo", "wget", "-O", "/usr/local/bin/mkcert",
					"https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-amd64"
				], check=True)
				subprocess.run(["sudo", "chmod", "+x", "/usr/local/bin/mkcert"], check=True)
				
			elif "fedora" in os_release or "rhel" in os_release or "centos" in os_release:
				print("[cyan]→ Installing mkcert via dnf/yum...[/]")
				subprocess.run(["sudo", "dnf", "install", "-y", "nss-tools"], check=True)
				subprocess.run([
					"sudo", "wget", "-O", "/usr/local/bin/mkcert",
					"https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-amd64"
				], check=True)
				subprocess.run(["sudo", "chmod", "+x", "/usr/local/bin/mkcert"], check=True)
				
			elif "arch" in os_release:
				print("[cyan]→ Installing mkcert via pacman...[/]")
				subprocess.run(["sudo", "pacman", "-S", "--noconfirm", "mkcert"], check=True)
				
			else:
				print("[yellow]Unknown Linux distribution. Please install mkcert manually:[/]")
				print("  https://github.com/FiloSottile/mkcert#installation")
				return False
				
		elif system == "windows":
			print("[cyan]→ Installing mkcert via Chocolatey...[/]")
			print("[yellow]Note: You may need to run as Administrator[/]")
			subprocess.run(["choco", "install", "mkcert"], check=True)
			
		else:
			print(f"[red]Unsupported OS: {system}[/]")
			print("[yellow]Please install mkcert manually:[/]")
			print("  https://github.com/FiloSottile/mkcert#installation")
			return False
			
		print("[green]✔ mkcert installed successfully[/]")
		return True
		
	except subprocess.CalledProcessError as e:
		print(f"[red]Installation failed: {e}[/]")
		return False
	except FileNotFoundError as e:
		print(f"[red]Package manager not found: {e}[/]")
		print("[yellow]Please install mkcert manually:[/]")
		print("  https://github.com/FiloSottile/mkcert#installation")
		return False


def install_root_ca() -> bool:
	"""Install mkcert's root CA in system trust store."""
	try:
		print("[cyan]→ Installing mkcert root CA...[/]")
		result = subprocess.run(["mkcert", "-install"], capture_output=True, text=True)
		
		if result.returncode == 0:
			print("[green]✔ Root CA installed in system trust store[/]")
			print("[dim]Your browser will now trust certificates generated by mkcert[/]")
			return True
		else:
			print(f"[red]Failed to install root CA: {result.stderr}[/]")
			return False
			
	except Exception as e:
		print(f"[red]Error installing root CA: {e}[/]")
		return False


def generate_local_cert(domain: str, cert_dir: Path) -> bool:
	"""
	Generate a local certificate for the given domain using mkcert.
	
	Args:
		domain: The domain name (e.g., "cirrondly.local")
		cert_dir: Directory to save the certificates (e.g., letsencrypt/live/cirrondly.local)
	
	Returns:
		True if successful, False otherwise
	"""
	cert_dir.mkdir(parents=True, exist_ok=True)
	
	fullchain = cert_dir / "fullchain.pem"
	privkey = cert_dir / "privkey.pem"
	
	try:
		print(f"[cyan]→ Generating certificate for {domain}...[/]")
		
		# Generate cert for both the domain and wildcard subdomain
		result = subprocess.run([
			"mkcert",
			"-cert-file", str(fullchain),
			"-key-file", str(privkey),
			domain,
			f"*.{domain}"
		], capture_output=True, text=True)
		
		if result.returncode == 0:
			print(f"[green]✔ Certificate generated:[/]")
			print(f"    {fullchain}")
			print(f"    {privkey}")
			return True
		else:
			print(f"[red]Failed to generate certificate: {result.stderr}[/]")
			return False
			
	except Exception as e:
		print(f"[red]Error generating certificate: {e}[/]")
		return False


def setup_local_certs(domains: list[str], cwd: Path) -> bool:
	"""
	Complete setup of local certificates for the given domains.
	
	1. Check if mkcert is installed
	2. Install mkcert if not found (with user confirmation)
	3. Install root CA
	4. Generate certificates for all domains
	
	Args:
		domains: List of domain names to generate certificates for
		cwd: Current working directory (where letsencrypt/ should be created)
	
	Returns:
		True if all operations successful, False otherwise
	"""
	# Check if mkcert is installed
	mkcert_path = detect_mkcert()
	
	if not mkcert_path:
		print("[yellow]mkcert is not installed.[/]")
		print("\nmkcert generates locally-trusted development certificates.")
		print("Learn more: https://github.com/FiloSottile/mkcert\n")
		
		if not typer.confirm("Would you like to install mkcert now?", default=True):
			print("[yellow]Aborting. Install mkcert manually and try again.[/]")
			return False
		
		if not install_mkcert():
			return False
		
		# Verify installation
		mkcert_path = detect_mkcert()
		if not mkcert_path:
			print("[red]mkcert installation failed or not in PATH[/]")
			return False
	
	print(f"[green]✔ mkcert found at: {mkcert_path}[/]")
	
	# Install root CA
	if not install_root_ca():
		print("[yellow]Warning: Root CA installation failed. Certificates will not be trusted.[/]")
		if not typer.confirm("Continue anyway?", default=False):
			return False
	
	# Generate certificates for each domain
	le_dir = cwd / "letsencrypt" / "live"
	success_count = 0
	
	for domain in domains:
		cert_dir = le_dir / domain
		if generate_local_cert(domain, cert_dir):
			success_count += 1
		else:
			print(f"[yellow]Skipping {domain} due to error[/]")
	
	if success_count == 0:
		print("[red]No certificates were generated successfully[/]")
		return False
	
	print(f"\n[green]✔ Generated {success_count}/{len(domains)} certificate(s)[/]")
	return True
