import anyio
import logging
import httpx
from src.config import (
    AEROS_BASE_URL, 
    WINDOWS_AEROS_BASE_URL, 
    VAULT_URL, 
    ROLE_ID, 
    SECRET_ID, 
    AEROS_SECRET_PATH, 
    AEROS_LICENSE_ID, 
    AEROS_LICENSE_SECRET,
    USE_LICENSE_APP
)
from src.utils import get_vault_secrets

log = logging.getLogger(__name__)

# Try to import licaeros gracefully
try:
    from licaeros import LicensedSession, device_fingerprint_hex
    HAS_LICAEROS = True
except ImportError:
    HAS_LICAEROS = False
    log.warning("licaeros library not found. Falling back to direct httpx calls if enabled.")

# Initialize a global session if possible, or create on demand
_aeros_session = None

def get_aeros_session(base_url):
    global _aeros_session
    
    if not USE_LICENSE_APP or not HAS_LICAEROS:
        if _aeros_session is None or not isinstance(_aeros_session, httpx.Client) or str(_aeros_session.base_url) != str(base_url):
            log.info(f"Using direct httpx.Client for base URL: {base_url}")
            _aeros_session = httpx.Client(base_url=base_url, timeout=300.0)
        return _aeros_session

    # License App path - only proceed if USE_LICENSE_APP is True
    license_id = AEROS_LICENSE_ID
    license_secret = AEROS_LICENSE_SECRET

    # If vault is configured, try to get from there
    if VAULT_URL and ROLE_ID and SECRET_ID and AEROS_SECRET_PATH:
        results = get_vault_secrets(
            vault_url=VAULT_URL,
            role_id=ROLE_ID,
            secret_id=SECRET_ID,
            secret_path=AEROS_SECRET_PATH,
            secret_keys_to_be_returned=['aeros_license_id', 'aeros_license_secret']
        )
        if results:
            license_id = results['aeros_license_id']
            license_secret = results['aeros_license_secret']
            log.info("Aeros license retrieved from Vault")
        else:
            log.warning("Failed to get Aeros license from Vault, trying local env fallback")

    if not license_id or not license_secret:
        log.warning("Aeros license ID or Secret not provided. Falling back to direct httpx.")
        if _aeros_session is None or not isinstance(_aeros_session, httpx.Client):
            _aeros_session = httpx.Client(base_url=base_url, timeout=300.0)
        return _aeros_session

    if _aeros_session is None or isinstance(_aeros_session, httpx.Client):
        log.info(f"Initializing LicensedSession with base URL: {base_url}")
        log.info(f"Encrypted Device ID: {device_fingerprint_hex()}")
        _aeros_session = LicensedSession(
            api_base=base_url,
            license_id=license_id,
            license_secret=license_secret,
            timeout=1000
        )
    return _aeros_session

async def aeros_post(path: str, json=None, data=None, **kwargs):
    """
    Asynchronous wrapper for Aeros requests (Licensed or Direct)
    """
    # If not using license app, fetch from AEROS_BASE_URL direcly
    target_base_url = WINDOWS_AEROS_BASE_URL if USE_LICENSE_APP and HAS_LICAEROS else AEROS_BASE_URL
    session = get_aeros_session(target_base_url)
    
    # Path logic: License app often uses /api/aeros prefix, direct might not.
    # However, to maintain compatibility with existing code calling this with path="/api/Project/ImportAROFile"
    # we should decide if we need to adjust the path.
    # User said: "system still fetch to aeros direcly not to licence app then lincense app forward it to aeros"
    # This implies the license app acts as a proxy for /api/aeros/ paths.
    
    if USE_LICENSE_APP and HAS_LICAEROS:
        url = f"/api/aeros{path}"
        response = await anyio.to_thread.run_sync(
            lambda: session.post(url, json_data=json, data=data, headers=kwargs.get("headers"))
        )
    else:
        # Direct fetch from Aeros might have different path structure?
        # Assuming direct Aeros path is same as what the license app proxies to.
        url = path
        response = await anyio.to_thread.run_sync(
            lambda: session.post(url, json=json, data=data, headers=kwargs.get("headers"))
        )
        
    return response


async def aeros_file_upload(path, file, field_name, filename, base_url=None):
    target_base_url = WINDOWS_AEROS_BASE_URL if USE_LICENSE_APP and HAS_LICAEROS else (base_url or AEROS_BASE_URL)
    session = get_aeros_session(target_base_url)
    
    if USE_LICENSE_APP and HAS_LICAEROS:
        url = f"/api/aeros{path}"
        response = await anyio.to_thread.run_sync(
            lambda: session.post_multipart(url, file, field_name, filename)
        )
    else:
        url = "/upload-file"
        files = {field_name: (filename, file)}
        response = await anyio.to_thread.run_sync(
            lambda: session.post(url, files=files)
        )
        
    return response