import os
import json
import logging
import asyncio
import aiohttp
from datetime import datetime, timedelta
from typing import Optional, List, Dict

logger = logging.getLogger(__name__)

class DatabaseTokenLoader:
    """Load tokens from Laravel database via API"""

    def __init__(self, api_base_url: str = None, api_key: str = None):
        self.api_base_url = api_base_url or os.environ.get('LARAVEL_API_URL', 'http://127.0.0.1:9000')
        self.api_key = api_key or os.environ.get('ADMIN_API_KEY', 'locket-gold-secret-2024')
        self._cache = []
        self._cache_time = None
        self._cache_ttl = 60  # Cache tokens for 60 seconds

    async def fetch_tokens(self) -> List[Dict]:
        """Fetch active tokens from Laravel database"""
        cache_age = (datetime.now() - self._cache_time).total_seconds() if self._cache_time else 999

        # Return cached tokens if still valid
        if self._cache and cache_age < self._cache_ttl:
            return self._cache

        url = f"{self.api_base_url}/api/token-sets"
        headers = {'X-Admin-Key': self.api_key}

        try:
            async with aiohttp.ClientSession() as session:
                async with session.get(url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp:
                    if resp.status == 200:
                        data = await resp.json()
                        if data.get('success'):
                            self._cache = data.get('tokens', [])
                            self._cache_time = datetime.now()
                            logger.info(f"[TokenLoader] Loaded {len(self._cache)} tokens from database")
                            return self._cache
                    else:
                        logger.warning(f"[TokenLoader] API returned status {resp.status}")
        except Exception as e:
            logger.error(f"[TokenLoader] Failed to fetch tokens: {e}")

        # Return cached tokens as fallback (even if expired)
        if self._cache:
            logger.info("[TokenLoader] Using cached tokens due to fetch failure")
            return self._cache

        return []

    async def mark_token_used(self, token_id: int):
        """Mark a token as used in the database"""
        url = f"{self.api_base_url}/api/token-sets/{token_id}/used"
        headers = {'X-Admin-Key': self.api_key}

        try:
            async with aiohttp.ClientSession() as session:
                async with session.post(url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp:
                    if resp.status == 200:
                        data = await resp.json()
                        logger.info(f"[TokenLoader] Marked token #{token_id} as used")
                        return data
                    else:
                        logger.warning(f"[TokenLoader] Failed to mark token used: status {resp.status}")
        except Exception as e:
            logger.error(f"[TokenLoader] Failed to mark token used: {e}")

        return None

    def clear_cache(self):
        """Clear the token cache"""
        self._cache = []
        self._cache_time = None
        logger.info("[TokenLoader] Cache cleared")


def load_token_sets_from_config() -> List[Dict]:
    """Load TOKEN_SETS from config.py as fallback"""
    from app.config import TOKEN_SETS as LEGACY_TOKEN_SETS

    tokens = []
    for idx, ts in enumerate(LEGACY_TOKEN_SETS):
        tokens.append({
            'id': -(idx + 1),  # Negative IDs for legacy tokens
            'name': ts.get('name', f'Legacy Token #{idx + 1}'),
            'fetch_token': ts.get('fetch_token', ''),
            'app_transaction': ts.get('app_transaction', ''),
            'hash_params': ts.get('hash_params'),
            'hash_headers': ts.get('hash_headers'),
            'is_sandbox': ts.get('is_sandbox', False),
            'cooldown_seconds': ts.get('cooldown_seconds', 15),
        })
    return tokens
