"""License verification for aicert-pro using Ed25519 signatures."""

import base64
import os
import sys
from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Optional

from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.hazmat.primitives import serialization
from cryptography.exceptions import InvalidSignature

# Embedded Ed25519 public key for license verification (placeholder)
# Replace with actual public key for production
LICENSE_PUBLIC_KEY = ed25519.Ed25519PublicKey.from_public_bytes(
    base64.b64decode(
        "ewWxgkhpOJpLGcQKky3gMuEKaBlvlEZjy9MJ6YYCpuY="
    )
)

LICENSE_ENV_VAR = "AICERT_PRO_LICENSE"


class LicenseError(Exception):
    """Base exception for license errors."""

    exit_code = 5


class LicenseMissingError(LicenseError):
    """Raised when license is not found."""

    def __init__(self) -> None:
        super().__init__("License not found. Set AICERT_PRO_LICENSE environment variable.")


class LicenseInvalidError(LicenseError):
    """Raised when license signature is invalid."""

    def __init__(self) -> None:
        super().__init__("License signature is invalid.")


class LicenseExpiredError(LicenseError):
    """Raised when license has expired."""

    def __init__(self, expired_at: str) -> None:
        super().__init__(f"License expired at {expired_at}.")


@dataclass
class LicenseData:
    """License data parsed from base64-encoded JSON."""

    license_id: str
    owner: str
    issued_at: str
    expires_at: Optional[str] = None
    features: Optional[list[str]] = None
    signature: Optional[str] = None

    @property
    def is_expired(self) -> bool:
        """Check if license is expired."""
        if self.expires_at is None:
            return False
        try:
            expires = datetime.fromisoformat(self.expires_at.replace("Z", "+00:00"))
            return datetime.now(timezone.utc) > expires
        except ValueError:
            return False


def verify_license(license_data: LicenseData) -> bool:
    """Verify Ed25519 signature on license data.
    
    Args:
        license_data: Parsed license data including signature.
        
    Returns:
        True if signature is valid.
        
    Raises:
        LicenseInvalidError: If signature verification fails.
        LicenseExpiredError: If license has expired.
    """
    if license_data.is_expired:
        raise LicenseExpiredError(license_data.expires_at)
    
    if license_data.signature is None:
        raise LicenseInvalidError()
    
    # Create signable payload (license data without signature)
    payload = f"{license_data.license_id}:{license_data.owner}:{license_data.issued_at}"
    if license_data.expires_at:
        payload += f":{license_data.expires_at}"
    if license_data.features:
        payload += f":{','.join(license_data.features)}"
    
    try:
        signature_bytes = base64.b64decode(license_data.signature)
        LICENSE_PUBLIC_KEY.verify(signature_bytes, payload.encode("utf-8"))
    except (InvalidSignature, ValueError) as e:
        raise LicenseInvalidError()
    
    return True


def read_license_from_env() -> str:
    """Read license string from environment variable.
    
    Returns:
        Base64-encoded license string.
        
    Raises:
        LicenseMissingError: If environment variable is not set.
    """
    license_str = os.environ.get(LICENSE_ENV_VAR)
    if not license_str:
        raise LicenseMissingError()
    return license_str


def require_pro() -> LicenseData:
    """Require and verify a valid pro license.
    
    Returns:
        Parsed and verified license data.
        
    Exits:
        Exit code 5 if license is missing or invalid.
    """
    try:
        license_str = read_license_from_env()
        import json
        data = json.loads(base64.b64decode(license_str))
        license_data = LicenseData(**data)
        verify_license(license_data)
        return license_data
    except LicenseError:
        raise
    except Exception:
        raise LicenseInvalidError()
