"""
License validation and activation with hardware binding.
"""
import os
import json
from pathlib import Path
from typing import Optional, Dict, Any
from datetime import datetime
import httpx
import structlog
from datashaper.licensing.hardware import HardwareFingerprint

logger = structlog.get_logger(__name__)


class LicenseValidator:
    """Validate and manage license keys with hardware binding."""
    
    LICENSE_DIR = Path.home() / ".datashaper"
    LICENSE_FILE = LICENSE_DIR / "license.json"
    API_URL = os.getenv("DATASHAPER_API_URL", "https://api.datashaper.ai")
    
    def __init__(self):
        self.LICENSE_DIR.mkdir(exist_ok=True)
        self.hw_fingerprint = HardwareFingerprint()
    
    def validate(self, license_key: Optional[str] = None) -> Optional[Dict[str, Any]]:
        """
        Validate a license key (online or local).
        
        Args:
            license_key: License key to validate (or None to use local)
            
        Returns:
            License info dict or None if invalid
        """
        # Try environment variable
        if not license_key:
            license_key = os.getenv("DATASHAPER_LICENSE")
        
        # Try local license file
        if not license_key:
            return self.get_local_license()
        
        # Validate online (if available)
        try:
            return self._validate_online(license_key)
        except Exception as e:
            logger.warning("online_validation_failed", error=str(e))
            # Fall back to local if online fails
            return self.get_local_license()
    
    def _validate_online(self, license_key: str) -> Optional[Dict[str, Any]]:
        """Validate license key via API."""
        try:
            machine_id = self.hw_fingerprint.get_machine_id()
            
            response = httpx.post(
                f"{self.API_URL}/license-status",
                json={
                    "license_key": license_key,
                    "machine_id": machine_id
                },
                timeout=5.0
            )
            
            if response.status_code == 200:
                data = response.json()
                if data.get("valid"):
                    license_info = {
                        "license_key": license_key,
                        "tier": data.get("tier", "free"),
                        "expiry": data.get("expiry"),
                        "days_remaining": data.get("days_remaining"),
                        "machine_id": machine_id,
                        "activated_at": datetime.now().isoformat()
                    }
                    
                    # Cache locally for offline use
                    self._save_license(license_info)
                    
                    return license_info
            
            logger.warning("license_validation_failed", status=response.status_code)
            return None
            
        except Exception as e:
            logger.error("license_validation_error", error=str(e))
            return None
    
    def get_local_license(self) -> Optional[Dict[str, Any]]:
        """Get locally stored license and verify hardware binding."""
        if not self.LICENSE_FILE.exists():
            return {"tier": "free"}  # Default to free tier
        
        try:
            with open(self.LICENSE_FILE) as f:
                license_data = json.load(f)
            
            # Verify hardware binding (if exists)
            stored_machine_id = license_data.get("machine_id")
            if stored_machine_id:
                current_machine_id = self.hw_fingerprint.get_machine_id()
                
                if stored_machine_id != current_machine_id:
                    logger.warning("hardware_mismatch",
                                 stored=stored_machine_id[:8],
                                 current=current_machine_id[:8])
                    # License bound to different machine
                    return {"tier": "free", "error": "License bound to different machine"}
            
            # Check expiry (for monthly/yearly subscriptions)
            expiry = license_data.get("expiry")
            if expiry:
                expiry_date = datetime.fromisoformat(expiry)
                if datetime.now() > expiry_date:
                    logger.warning("license_expired", expiry=expiry)
                    return {"tier": "free", "error": "License expired"}
            
            return license_data
            
        except Exception as e:
            logger.error("local_license_read_failed", error=str(e))
            return {"tier": "free"}
    
    def activate(self, license_key: str) -> Optional[Dict[str, Any]]:
        """
        Activate a license key on this machine.
        
        Args:
            license_key: License key to activate
            
        Returns:
            License info dict or None if invalid
        """
        # Get hardware fingerprint
        machine_id = self.hw_fingerprint.get_machine_id()
        
        # Validate online with hardware binding
        try:
            response = httpx.post(
                f"{self.API_URL}/validate-license",
                json={
                    "license_key": license_key,
                    "machine_id": machine_id,
                    "action": "activate"
                },
                timeout=10.0
            )
            
            if response.status_code == 200:
                data = response.json()
                if data.get("valid"):
                    license_info = {
                        "license_key": license_key,
                        "tier": data.get("tier", "free"),
                        "expiry": data.get("expiry"),
                        "machine_id": machine_id,
                        "activated_at": datetime.now().isoformat()
                    }
                    
                    # Save locally
                    self._save_license(license_info)
                    
                    logger.info("license_activated",
                              tier=license_info.get("tier"),
                              machine_id=machine_id[:8])
                    
                    return license_info
                else:
                    logger.warning("license_invalid", reason=data.get("reason"))
                    return None
            else:
                logger.error("activation_failed", status=response.status_code)
                return None
                
        except httpx.ConnectError:
            logger.error("activation_offline",
                        message="Cannot reach license server. Check internet connection.")
            return None
        except Exception as e:
            logger.error("activation_error", error=str(e))
            return None
    
    def _save_license(self, license_info: Dict[str, Any]):
        """Save license to local file."""
        with open(self.LICENSE_FILE, 'w') as f:
            json.dump(license_info, f, indent=2)
    
    def deactivate(self):
        """Deactivate license on this machine."""
        if self.LICENSE_FILE.exists():
            self.LICENSE_FILE.unlink()
            logger.info("license_deactivated")

