from fastapi import APIRouter, Depends, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession
from redis.asyncio import Redis
from app.dependencies import get_db, get_current_user, get_redis
from app.config import get_settings
from app.modules.user.models import User
from app.modules.terminal.auto.service import TerminalService
from app.modules.terminal.auto.schema import (
    DeployConfig,
    InstanceResponse,
    InstanceListResponse,
    InstanceControlRequest,
    InstanceStatusUpdate,
    PresetCreate,
    PresetUpdate,
    PresetResponse,
    PresetListResponse,
    TelegramBotCreate,
    TelegramBotUpdate,
    TelegramBotResponse,
    TelegramBotListResponse,
)
from app.middleware.rate_limiter import endpoint_rate_limit

router = APIRouter()


@router.get("/recent-events")
async def get_recent_events(
    current_user: User = Depends(get_current_user),
):
    """Get user's recent market deployments"""
    return {"recent_events": current_user.recent_events or []}


@router.post("/logout")
async def logout_terminal(
    credentials: HTTPAuthorizationCredentials = Depends(HTTPBearer()),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis)
):
    """Clear terminal session credentials and blacklist JWT token"""
    service = TerminalService(db, current_user.id, redis)
    await service.clear_session_credentials()
    # Blacklist the JWT so it can't be reused after logout
    settings = get_settings()
    token_ttl = settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
    await redis.setex(f"blacklist:{credentials.credentials}", token_ttl, "1")
    return {"message": "Logged out successfully"}


@router.post("/deploy", response_model=InstanceResponse, status_code=status.HTTP_201_CREATED)
async def deploy_instance(
    config: DeployConfig,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(5, 60))
):
    """Deploy new trading instance - Rate limit: 5/min"""
    service = TerminalService(db, current_user.id, redis)
    instance = await service.deploy_instance(config)
    return service.format_instance_response(instance)


@router.get("/instances", response_model=InstanceListResponse)
async def list_instances(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis)
):
    """List all trading instances"""
    service = TerminalService(db, current_user.id, redis)
    instances = await service.get_user_instances()
    
    formatted = [service.format_instance_response(inst) for inst in instances]
    return InstanceListResponse(instances=formatted, total=len(formatted))


@router.get("/instances/{instance_id}", response_model=InstanceResponse)
async def get_instance(
    instance_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis)
):
    """Get specific instance"""
    service = TerminalService(db, current_user.id, redis)
    instance = await service.get_instance(instance_id)
    return service.format_instance_response(instance)


@router.get("/instances/{instance_id}/status", response_model=InstanceStatusUpdate)
async def get_instance_status(
    instance_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis)
):
    """Get real-time status"""
    service = TerminalService(db, current_user.id, redis)
    status_data = await service.get_instance_status(instance_id)
    return status_data


@router.delete("/instances/{instance_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_instance(
    instance_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(10, 60))
):
    """Delete stopped instance - Rate limit: 10/min"""
    service = TerminalService(db, current_user.id, redis)
    instance = await service.get_instance(instance_id)
    
    from app.modules.terminal.auto.models import InstanceStatus
    if instance.status not in [InstanceStatus.STOPPED, InstanceStatus.ERROR]:
        from app.core.exceptions import BadRequestError
        raise BadRequestError("Can only delete stopped instances")
    
    await db.delete(instance)
    await db.commit()


@router.post("/instances/{instance_id}/control", response_model=InstanceResponse)
async def control_instance(
    instance_id: int,
    control_request: InstanceControlRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(20, 60))
):
    """Control instance - Rate limit: 20/min"""
    service = TerminalService(db, current_user.id, redis)
    
    if control_request.action == "cancel_orders":
        await service.cancel_orders_instance(instance_id)
        instance = await service.get_instance(instance_id)
    elif control_request.action in ("pause", "resume", "toggle_pause"):
        await service.toggle_pause_instance(instance_id)
        instance = await service.get_instance(instance_id)
    elif control_request.action == "single_fire":
        await service.single_fire_instance(instance_id)
        instance = await service.get_instance(instance_id)
    elif control_request.action == "stop":
        instance = await service.stop_instance(instance_id)
    elif control_request.action == "force_stop":
        instance = await service.force_stop_instance(instance_id)
    elif control_request.action == "end":
        instance = await service.end_instance(instance_id)
    elif control_request.action in ("accept_next_market", "decline_next_market"):
        command_key = f"trading:instance:{instance_id}:command"
        cmd = {"action": control_request.action}
        if control_request.next_market:
            cmd["next_market"] = control_request.next_market
        import json as _json
        await redis.rpush(command_key, _json.dumps(cmd))
        instance = await service.get_instance(instance_id)
    else:
        from app.core.exceptions import BadRequestError
        raise BadRequestError(f"Invalid action: {control_request.action}")
    
    return service.format_instance_response(instance)

@router.post("/instances/{instance_id}/fair_value")
async def toggle_fair_value(
    instance_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(30, 60))
):
    """Toggle fair value - Rate limit: 30/min"""
    service = TerminalService(db, current_user.id, redis)
    result = await service.toggle_fair_value_instance(instance_id)
    return result


class JumpRequest(BaseModel):
    market_index: int = Field(0, ge=0, le=1)


@router.post("/instances/{instance_id}/jump", response_model=dict)
async def toggle_jump(
    instance_id: int,
    jump_request: JumpRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(30, 60))
):
    """Toggle jump mode - Rate limit: 30/min"""
    service = TerminalService(db, current_user.id, redis)
    result = await service.toggle_jump(instance_id, jump_request.market_index)
    return result


# ── Presets ─────────────────────────────────────────────────

@router.get("/presets", response_model=PresetListResponse)
async def list_presets(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(30, 60))
):
    """List all saved strategy presets - Rate limit: 30/min"""
    service = TerminalService(db, current_user.id, redis)
    presets = await service.get_presets()
    return PresetListResponse(
        presets=[PresetResponse.model_validate(p) for p in presets],
        total=len(presets),
    )


@router.post("/presets", response_model=PresetResponse, status_code=status.HTTP_201_CREATED)
async def create_preset(
    preset_data: PresetCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(10, 60))
):
    """Save a new strategy preset"""
    service = TerminalService(db, current_user.id, redis)
    preset = await service.create_preset(preset_data.name, preset_data.strategy_config, username=current_user.username)
    return PresetResponse.model_validate(preset)


@router.get("/presets/{preset_id}", response_model=PresetResponse)
async def get_preset(
    preset_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(30, 60))
):
    """Get a specific preset - Rate limit: 30/min"""
    service = TerminalService(db, current_user.id, redis)
    preset = await service.get_preset(preset_id)
    return PresetResponse.model_validate(preset)


@router.put("/presets/{preset_id}", response_model=PresetResponse)
async def update_preset(
    preset_id: int,
    preset_data: PresetUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(10, 60))
):
    """Update a preset - Rate limit: 10/min"""
    service = TerminalService(db, current_user.id, redis)
    preset = await service.update_preset(preset_id, preset_data.name, preset_data.strategy_config)
    return PresetResponse.model_validate(preset)


@router.delete("/presets/{preset_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_preset(
    preset_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(10, 60))
):
    """Delete a preset (creator or admin) - Rate limit: 10/min"""
    service = TerminalService(db, current_user.id, redis)
    await service.delete_preset(preset_id, is_admin=current_user.is_superuser)


# ── Telegram Bots ──────────────────────────────────────────

@router.get("/telegram-bots", response_model=TelegramBotListResponse)
async def list_telegram_bots(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(30, 60))
):
    """List user's saved Telegram bots"""
    service = TerminalService(db, current_user.id, redis)
    bots = await service.get_telegram_bots()
    return TelegramBotListResponse(
        bots=[TelegramBotResponse.model_validate(b) for b in bots],
        total=len(bots),
    )


@router.post("/telegram-bots", response_model=TelegramBotResponse, status_code=status.HTTP_201_CREATED)
async def create_telegram_bot(
    bot_data: TelegramBotCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(10, 60))
):
    """Save a new Telegram bot"""
    service = TerminalService(db, current_user.id, redis)
    bot = await service.create_telegram_bot(bot_data.name, bot_data.bot_token, bot_data.chat_id)
    return TelegramBotResponse.model_validate(bot)


@router.put("/telegram-bots/{bot_id}", response_model=TelegramBotResponse)
async def update_telegram_bot(
    bot_id: int,
    bot_data: TelegramBotUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(10, 60))
):
    """Update a saved Telegram bot"""
    service = TerminalService(db, current_user.id, redis)
    bot = await service.update_telegram_bot(bot_id, bot_data.name, bot_data.bot_token, bot_data.chat_id)
    return TelegramBotResponse.model_validate(bot)


@router.delete("/telegram-bots/{bot_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_telegram_bot(
    bot_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
    _rate_limit: bool = Depends(endpoint_rate_limit(10, 60))
):
    """Delete a saved Telegram bot (must not be active)"""
    service = TerminalService(db, current_user.id, redis)
    await service.delete_telegram_bot(bot_id)