from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from datetime import datetime, timedelta
from typing import Dict, Any
import uuid

from app.db.database import get_db
from app.models.models import License, Activation, Version
from app.schemas.license import (
    LicenseActivationRequest,
    LicenseActivationResponse,
    LicenseVerificationRequest,
    LicenseVerificationResponse,
    SessionStartRequest,
    SessionStartResponse,
    SessionHeartbeatRequest,
    SessionHeartbeatResponse,
    SessionEndRequest,
    SessionEndResponse
)
from app.core.security import get_api_key
from app.core.config import settings
from app.core.api_key_auth import validate_api_key

router = APIRouter()

@router.post("/activate", response_model=LicenseActivationResponse)
async def activate_license(
    request: LicenseActivationRequest,
    db: Session = Depends(get_db),
    api_key: str = Depends(validate_api_key)
):
    license = db.query(License).filter(
        License.license_key == request.license_key,
        License.is_active == True
    ).first()
    
    if not license:
        return LicenseActivationResponse(
            success=False,
            message="Invalid license key"
        )
    
    if license.expires_at and license.expires_at < datetime.utcnow():
        return LicenseActivationResponse(
            success=False,
            message="License has expired"
        )
    
    existing_activations = db.query(Activation).filter(
        Activation.license_id == license.id,
        Activation.is_active == True
    ).all()
    
    existing_machine = next(
        (a for a in existing_activations if a.machine_id == request.machine_id),
        None
    )
    
    if existing_machine:
        if existing_machine.hardware_hash != request.hardware_hash:
            return LicenseActivationResponse(
                success=False,
                message="Hardware mismatch for this machine"
            )
        
        existing_machine.last_heartbeat = datetime.utcnow()
        existing_machine.app_version = request.app_version
        existing_machine.os_info = request.os_info
        db.commit()
        
        return LicenseActivationResponse(
            success=True,
            message="License reactivated successfully",
            activation_id=existing_machine.id,
            expires_at=license.expires_at,
            features={"all_features": True}
        )
    
    if len(existing_activations) >= license.max_activations:
        return LicenseActivationResponse(
            success=False,
            message=f"Maximum activations ({license.max_activations}) reached"
        )
    
    new_activation = Activation(
        license_id=license.id,
        machine_id=request.machine_id,
        hardware_hash=request.hardware_hash,
        os_info=request.os_info,
        app_version=request.app_version
    )
    
    db.add(new_activation)
    db.commit()
    db.refresh(new_activation)
    
    return LicenseActivationResponse(
        success=True,
        message="License activated successfully",
        activation_id=new_activation.id,
        expires_at=license.expires_at,
        features={"all_features": True}
    )

@router.post("/verify", response_model=LicenseVerificationResponse)
async def verify_license(
    request: LicenseVerificationRequest,
    db: Session = Depends(get_db),
    api_key: str = Depends(validate_api_key)
):
    activation = db.query(Activation).filter(
        Activation.id == request.activation_id,
        Activation.machine_id == request.machine_id,
        Activation.is_active == True
    ).first()
    
    if not activation:
        return LicenseVerificationResponse(
            valid=False,
            message="Invalid activation"
        )
    
    license = activation.license
    
    if not license.is_active:
        return LicenseVerificationResponse(
            valid=False,
            message="License is no longer active"
        )
    
    if license.license_key != request.license_key:
        return LicenseVerificationResponse(
            valid=False,
            message="License key mismatch"
        )
    
    if activation.hardware_hash != request.hardware_hash:
        grace_period = datetime.utcnow() - timedelta(days=settings.OFFLINE_GRACE_PERIOD_DAYS)
        if activation.last_heartbeat < grace_period:
            return LicenseVerificationResponse(
                valid=False,
                message="Hardware mismatch and grace period expired"
            )
        else:
            return LicenseVerificationResponse(
                valid=True,
                message="Hardware mismatch but within grace period",
                expires_at=license.expires_at,
                features={"all_features": True}
            )
    
    if license.expires_at and license.expires_at < datetime.utcnow():
        return LicenseVerificationResponse(
            valid=False,
            message="License has expired"
        )
    
    activation.last_heartbeat = datetime.utcnow()
    db.commit()
    
    latest_version = db.query(Version).order_by(Version.release_date.desc()).first()
    requires_update = False
    update_url = None
    
    if latest_version and activation.app_version:
        if latest_version.version_number > activation.app_version:
            requires_update = True
            update_url = latest_version.download_url
    
    return LicenseVerificationResponse(
        valid=True,
        message="License is valid",
        expires_at=license.expires_at,
        features={"all_features": True},
        requires_update=requires_update,
        update_url=update_url
    )

@router.get("/info/{license_key}")
async def get_license_info(
    license_key: str,
    db: Session = Depends(get_db),
    api_key: str = Depends(validate_api_key)
):
    license = db.query(License).filter(
        License.license_key == license_key
    ).first()
    
    if not license:
        raise HTTPException(status_code=404, detail="License not found")
    
    activations = db.query(Activation).filter(
        Activation.license_id == license.id,
        Activation.is_active == True
    ).all()
    
    return {
        "license_key": license.license_key,
        "product_id": license.product_id,
        "customer_email": license.customer_email,
        "customer_name": license.customer_name,
        "is_active": license.is_active,
        "expires_at": license.expires_at,
        "max_activations": license.max_activations,
        "current_activations": len(activations),
        "activations": [
            {
                "id": a.id,
                "machine_id": a.machine_id,
                "activation_date": a.activation_date,
                "last_heartbeat": a.last_heartbeat,
                "app_version": a.app_version
            }
            for a in activations
        ]
    }

@router.post("/session/start", response_model=SessionStartResponse)
async def start_session(
    request: SessionStartRequest,
    db: Session = Depends(get_db),
    api_key: str = Depends(validate_api_key)
):
    # Verify API key matches client config
    from sqlalchemy import text
    result = db.execute(text("SELECT api_key, current_version, minimum_version FROM client_configs WHERE client_name = 'Account Forger'")).first()
    
    if not result or result.api_key != api_key:
        raise HTTPException(status_code=401, detail="Invalid API key")
    
    # Check if version is supported
    if request.version < result.minimum_version:
        return SessionStartResponse(
            success=False,
            message=f"Version {request.version} is too old. Minimum required: {result.minimum_version}",
            session_token=None,
            requires_update=True,
            update_url=None,
            whats_new=None
        )
    
    # Verify license exists and is active
    license = db.query(License).filter(
        License.license_key == request.license_key,
        License.is_active == True
    ).first()
    
    if not license:
        return SessionStartResponse(
            success=False,
            message="Invalid or inactive license key",
            session_token=None
        )
    
    if license.expires_at and license.expires_at < datetime.utcnow():
        return SessionStartResponse(
            success=False,
            message="License has expired",
            session_token=None
        )
    
    # Check for existing active session
    existing_session_result = db.execute(
        text("SELECT session_token, hardware_id FROM license_sessions WHERE license_id = :license_id"),
        {"license_id": license.id}
    ).first()
    
    if existing_session_result:
        if existing_session_result.hardware_id == request.hardware_id:
            # Same device, update heartbeat
            db.execute(
                text("UPDATE license_sessions SET last_heartbeat = CURRENT_TIMESTAMP WHERE session_token = :token"),
                {"token": existing_session_result.session_token}
            )
            db.commit()
            
            return SessionStartResponse(
                success=True,
                message="Existing session resumed",
                session_token=existing_session_result.session_token,
                requires_update=request.version < result.current_version,
                update_url=None,
                whats_new=None
            )
        else:
            return SessionStartResponse(
                success=False,
                message="Es ist nur eine Sitzung erlaubt, stelle sicher, dass nirgendwo sonst das Programm läuft",
                session_token=None
            )
    
    # Create new session
    session_token = str(uuid.uuid4())
    
    db.execute(
        text("""
            INSERT INTO license_sessions (license_id, hardware_id, ip_address, client_version, session_token)
            VALUES (:license_id, :hardware_id, :ip_address, :version, :token)
        """),
        {
            "license_id": license.id,
            "hardware_id": request.hardware_id,
            "ip_address": request.ip_address,
            "version": request.version,
            "token": session_token
        }
    )
    db.commit()
    
    return SessionStartResponse(
        success=True,
        message="Session started successfully",
        session_token=session_token,
        requires_update=request.version < result.current_version,
        update_url=None,
        whats_new=None
    )

@router.post("/session/heartbeat", response_model=SessionHeartbeatResponse)
async def session_heartbeat(
    request: SessionHeartbeatRequest,
    db: Session = Depends(get_db),
    api_key: str = Depends(validate_api_key)
):
    # Update heartbeat
    result = db.execute(
        text("""
            UPDATE license_sessions 
            SET last_heartbeat = CURRENT_TIMESTAMP 
            WHERE session_token = :token 
            RETURNING id
        """),
        {"token": request.session_token}
    ).first()
    
    if not result:
        return SessionHeartbeatResponse(
            success=False,
            message="Invalid or expired session"
        )
    
    db.commit()
    
    return SessionHeartbeatResponse(
        success=True,
        message="Heartbeat received"
    )

@router.post("/session/end", response_model=SessionEndResponse)
async def end_session(
    request: SessionEndRequest,
    db: Session = Depends(get_db),
    api_key: str = Depends(validate_api_key)
):
    # Get session info before deleting
    session_info = db.execute(
        text("""
            SELECT license_id, hardware_id, ip_address, client_version, started_at
            FROM license_sessions
            WHERE session_token = :token
        """),
        {"token": request.session_token}
    ).first()
    
    if not session_info:
        return SessionEndResponse(
            success=False,
            message="Session not found"
        )
    
    # Log to session history
    db.execute(
        text("""
            INSERT INTO session_history (license_id, hardware_id, ip_address, client_version, started_at, ended_at, end_reason)
            VALUES (:license_id, :hardware_id, :ip_address, :version, :started, CURRENT_TIMESTAMP, 'normal')
        """),
        {
            "license_id": session_info.license_id,
            "hardware_id": session_info.hardware_id,
            "ip_address": session_info.ip_address,
            "version": session_info.client_version,
            "started": session_info.started_at
        }
    )
    
    # Delete the session
    db.execute(
        text("DELETE FROM license_sessions WHERE session_token = :token"),
        {"token": request.session_token}
    )
    
    db.commit()
    
    return SessionEndResponse(
        success=True,
        message="Session ended"
    )