import asyncio
import json
import os
from pathlib import Path
from typing import Any, Dict, Optional
from tortoise import Tortoise

from upwork_fetcher.models.dbcontext import dbcontext
from upwork_fetcher.models.upwork_config import UpworkConfig


# Fallback to file if database is not available
CONFIG_DIR = Path.home() / ".upwork_fetcher"
CONFIG_FILE = CONFIG_DIR / "config.json"

# Global variable to store db_url
_db_url: Optional[str] = None


def set_db_url(db_url: str):
    """Set the database URL for config storage"""
    global _db_url
    _db_url = db_url


def get_db_url() -> Optional[str]:
    """Get the database URL, checking environment variable first"""
    return os.getenv("UPWORK_DB_URL") or _db_url


async def _load_config_from_db() -> Dict[str, Any]:
    """Load configuration from database"""
    db_url = get_db_url()
    if not db_url:
        return {}

    async with dbcontext.db_context(db_url=db_url):
        # Get the latest config entry
        config_entry = await UpworkConfig.first()
        print(config_entry)
        if config_entry:
            config_dict: Dict[str, Any] = {
                "db_url": config_entry.db_url,
                "access_token": config_entry.access_token,
                "refresh_token": config_entry.refresh_token,
                "token_type": config_entry.token_type,
                "expires_in": config_entry.expires_in,
                "client_id": config_entry.client_id,
                "client_secret": config_entry.client_secret,
                "redirect_uri": config_entry.redirect_uri,
                "code": config_entry.code,
            }
            print(f"{config_dict = }")
            # Remove None values
            return {k: v for k, v in config_dict.items() if v is not None}

        return {}


async def _save_config_to_db(data: Dict[str, Any]):
    """Save configuration to database"""
    db_url = get_db_url()
    if not db_url:
        raise ValueError("Database URL not set")

    async with dbcontext.db_context(db_url=db_url):
        # Get existing config or create new one
        config_entry = await UpworkConfig.first()

        if config_entry:
            # Update existing entry
            for key, value in data.items():
                if hasattr(config_entry, key):
                    setattr(config_entry, key, value)
            await config_entry.save()
        else:
            # Create new entry
            config_data: Dict[str, Any] = {"db_url": db_url}
            config_data.update(data)
            # Filter out None values to avoid database constraints
            config_data = {k: v for k, v in config_data.items() if v is not None}
            await UpworkConfig.create(**config_data)


def load_config(config_path: Path = CONFIG_FILE) -> Dict[str, Any]:
    """Load configuration from database or file"""
    db_url = get_db_url()

    if db_url:
        # Try to load from database
        try:
            return asyncio.get_event_loop().run_until_complete(_load_config_from_db())
        except Exception as e:
            print(f"Warning: Failed to load config from database: {e}")
            # Fall back to file

    # Fallback to file-based config
    if not config_path.exists():
        CONFIG_DIR.mkdir(parents=True, exist_ok=True)

    if not config_path.exists():
        data = {}
        with open(config_path, "w") as file:
            json.dump(data, file, indent=4)

    with open(config_path, "r") as file:
        return json.load(file)


def save_config(data: Dict[str, Any]):
    """Save configuration to database or file"""
    db_url = get_db_url()
    print(f"{data = }")
    if db_url:
        # Save to database
        try:
            asyncio.get_event_loop().run_until_complete(_save_config_to_db(data))

            # Also update db_url if provided
            if "db_url" in data:
                set_db_url(data["db_url"])
            return
        except Exception as e:
            print(f"Warning: Failed to save config to database: {e}")
            # Fall back to file

    # Fallback to file-based config
    try:
        with open(CONFIG_FILE, "r") as file:
            config = json.loads(file.read())
    except (FileNotFoundError, json.JSONDecodeError):
        config = {}

    config.update(data)

    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    with open(CONFIG_FILE, "w") as file:
        json.dump(config, file, indent=4)
