from typing import Dict, Any, Optional
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from sqlalchemy import select

from src.core.database import Exchange, get_database
from src.core.config import get_config
from src.security.key_manager import get_key_manager
from src.trading.paper_trading import get_paper_trading

router = APIRouter()


class RiskSettings(BaseModel):
    max_drawdown_percent: float
    daily_loss_limit_percent: float
    position_size_percent: float


class PaperTradingSettings(BaseModel):
    initial_capital: float
    fee_exchange: str = "coinbase"  # Which exchange's fee model to use


class LoggingSettings(BaseModel):
    level: str
    dir: str
    retention_days: int


class GeneralSettings(BaseModel):
    timezone: str = "UTC"
    theme: str = "dark"
    currency: str = "USD"


class ExchangeCreate(BaseModel):
    name: str
    api_key: Optional[str] = None
    api_secret: Optional[str] = None
    sandbox: bool = False
    read_only: bool = True
    enabled: bool = True


class ExchangeUpdate(BaseModel):
    api_key: Optional[str] = None
    api_secret: Optional[str] = None
    sandbox: Optional[bool] = None
    read_only: Optional[bool] = None
    enabled: Optional[bool] = None


@router.get("/risk")
async def get_risk_settings():
    """Get risk management settings."""
    try:
        config = get_config()
        return {
            "max_drawdown_percent": config.get("risk.max_drawdown_percent", 20.0),
            "daily_loss_limit_percent": config.get("risk.daily_loss_limit_percent", 5.0),
            "position_size_percent": config.get("risk.position_size_percent", 2.0),
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.put("/risk")
async def update_risk_settings(settings: RiskSettings):
    """Update risk management settings."""
    try:
        config = get_config()
        config.set("risk.max_drawdown_percent", settings.max_drawdown_percent)
        config.set("risk.daily_loss_limit_percent", settings.daily_loss_limit_percent)
        config.set("risk.position_size_percent", settings.position_size_percent)
        config.save()
        return {"status": "success"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/paper-trading")
async def get_paper_trading_settings():
    """Get paper trading settings."""
    try:
        config = get_config()
        fee_exchange = config.get("paper_trading.fee_exchange", "coinbase")
        
        # Get fee rates for current exchange
        fee_rates = config.get(f"trading.exchanges.{fee_exchange}.fees", 
                               config.get("trading.default_fees", {"maker": 0.001, "taker": 0.001}))
        
        return {
            "initial_capital": config.get("paper_trading.default_capital", 100.0),
            "fee_exchange": fee_exchange,
            "fee_rates": fee_rates,
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.put("/paper-trading")
async def update_paper_trading_settings(settings: PaperTradingSettings):
    """Update paper trading settings."""
    try:
        config = get_config()
        config.set("paper_trading.default_capital", settings.initial_capital)
        config.set("paper_trading.fee_exchange", settings.fee_exchange)
        config.save()
        return {"status": "success"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/paper-trading/fee-exchanges")
async def get_available_fee_exchanges():
    """Get available exchange fee models for paper trading."""
    try:
        config = get_config()
        exchanges_config = config.get("trading.exchanges", {})
        default_fees = config.get("trading.default_fees", {"maker": 0.001, "taker": 0.001})
        current = config.get("paper_trading.fee_exchange", "coinbase")
        
        exchanges = [{"name": "default", "fees": default_fees}]
        for name, data in exchanges_config.items():
            if "fees" in data:
                exchanges.append({
                    "name": name,
                    "fees": data["fees"]
                })
        
        return {
            "exchanges": exchanges,
            "current": current,
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/paper-trading/reset")
async def reset_paper_account():
    """Reset paper trading account."""
    try:
        paper_trading = get_paper_trading()
        # Reset to capital from config
        success = await paper_trading.reset()
        if success:
            return {"status": "success", "message": "Paper account reset successfully"}
        else:
            raise HTTPException(status_code=500, detail="Failed to reset paper account")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/logging")
async def get_logging_settings():
    """Get logging settings."""
    try:
        config = get_config()
        return {
            "level": config.get("logging.level", "INFO"),
            "dir": config.get("logging.dir", ""),
            "retention_days": config.get("logging.retention_days", 30),
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.put("/logging")
async def update_logging_settings(settings: LoggingSettings):
    """Update logging settings."""
    try:
        config = get_config()
        config.set("logging.level", settings.level)
        config.set("logging.dir", settings.dir)
        config.set("logging.retention_days", settings.retention_days)
        config.save()
        return {"status": "success"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/general")
async def get_general_settings():
    """Get general settings."""
    try:
        config = get_config()
        return {
            "timezone": config.get("general.timezone", "UTC"),
            "theme": config.get("general.theme", "dark"),
            "currency": config.get("general.currency", "USD"),
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.put("/general")
async def update_general_settings(settings: GeneralSettings):
    """Update general settings."""
    try:
        config = get_config()
        config.set("general.timezone", settings.timezone)
        config.set("general.theme", settings.theme)
        config.set("general.currency", settings.currency)
        config.save()
        return {"status": "success"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/exchanges")
async def create_exchange(exchange: ExchangeCreate):
    """Create a new exchange."""
    try:
        db = get_database()
        async with db.get_session() as session:
            from src.exchanges.factory import ExchangeFactory
            from src.exchanges.public_data import PublicDataAdapter
            
            # Check if this is a public data exchange
            adapter_class = None
            try:
                if hasattr(ExchangeFactory, '_adapters'):
                    adapter_class = ExchangeFactory._adapters.get(exchange.name.lower())
            except:
                pass
            is_public_data = adapter_class == PublicDataAdapter if adapter_class else False
            
            # Only require API keys for non-public-data exchanges
            if not is_public_data:
                if not exchange.api_key or not exchange.api_secret:
                    raise HTTPException(status_code=400, detail="API key and secret are required")
            
            new_exchange = Exchange(
                name=exchange.name,
                enabled=exchange.enabled
            )
            session.add(new_exchange)
            await session.flush()
            
            # Save credentials
            key_manager = get_key_manager()
            key_manager.update_exchange(
                new_exchange.id,
                api_key=exchange.api_key or "",
                api_secret=exchange.api_secret or "",
                read_only=exchange.read_only if not is_public_data else True,
                sandbox=exchange.sandbox if not is_public_data else False
            )
            
            await session.commit()
            return {"id": new_exchange.id, "name": new_exchange.name, "status": "created"}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.put("/exchanges/{exchange_id}")
async def update_exchange(exchange_id: int, exchange: ExchangeUpdate):
    """Update an existing exchange."""
    try:
        db = get_database()
        async with db.get_session() as session:
            stmt = select(Exchange).where(Exchange.id == exchange_id)
            result = await session.execute(stmt)
            exchange_obj = result.scalar_one_or_none()
            if not exchange_obj:
                raise HTTPException(status_code=404, detail="Exchange not found")
            
            key_manager = get_key_manager()
            credentials = key_manager.get_exchange_credentials(exchange_id)
            
            # Update credentials if provided
            if exchange.api_key is not None or exchange.api_secret is not None:
                key_manager.update_exchange(
                    exchange_id,
                    api_key=exchange.api_key or credentials.get('api_key', ''),
                    api_secret=exchange.api_secret or credentials.get('api_secret', ''),
                    read_only=exchange.read_only if exchange.read_only is not None else credentials.get('read_only', True),
                    sandbox=exchange.sandbox if exchange.sandbox is not None else credentials.get('sandbox', False)
                )
            
            if exchange.enabled is not None:
                exchange_obj.enabled = exchange.enabled
                await session.commit()
            
            return {"status": "success"}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/exchanges/{exchange_id}")
async def delete_exchange(exchange_id: int):
    """Delete an exchange."""
    try:
        db = get_database()
        async with db.get_session() as session:
            stmt = select(Exchange).where(Exchange.id == exchange_id)
            result = await session.execute(stmt)
            exchange = result.scalar_one_or_none()
            if not exchange:
                raise HTTPException(status_code=404, detail="Exchange not found")
            
            await session.delete(exchange)
            await session.commit()
            return {"status": "success"}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/exchanges/{exchange_id}/test")
async def test_exchange_connection(exchange_id: int):
    """Test exchange connection."""
    try:
        db = get_database()
        async with db.get_session() as session:
            stmt = select(Exchange).where(Exchange.id == exchange_id)
            result = await session.execute(stmt)
            exchange = result.scalar_one_or_none()
            if not exchange:
                raise HTTPException(status_code=404, detail="Exchange not found")
            
            from src.exchanges.factory import ExchangeFactory
            from src.exchanges.public_data import PublicDataAdapter
            
            # Get adapter class safely
            adapter_class = None
            try:
                if hasattr(ExchangeFactory, '_adapters'):
                    adapter_class = ExchangeFactory._adapters.get(exchange.name.lower())
            except:
                pass
            is_public_data = adapter_class == PublicDataAdapter if adapter_class else False
            
            key_manager = get_key_manager()
            if not is_public_data and not key_manager.get_exchange_credentials(exchange_id):
                raise HTTPException(status_code=400, detail="No credentials found for this exchange")
            
            adapter = ExchangeFactory.create(exchange_id)
            if adapter and adapter.connect():
                try:
                    if is_public_data:
                        adapter.get_ticker("BTC/USDT")
                    else:
                        adapter.get_balance()
                    return {"status": "success", "message": "Connection successful"}
                except Exception as e:
                    return {"status": "error", "message": f"Connected but failed to fetch data: {str(e)}"}
            else:
                return {"status": "error", "message": "Failed to connect"}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
