"""
Scanner endpoints: deploy/stop/list market scanners.

- Kalshi scanner: polls for new markets matching a prefix, notifies via Telegram
- Turbine scanner: watches for trades from specific wallets, notifies via Telegram
"""

import json
import re
from datetime import datetime

from fastapi import APIRouter, Depends, Request
from fastapi.responses import Response
from sqlalchemy.ext.asyncio import AsyncSession
from redis.asyncio import Redis

from app.dependencies import get_db, get_current_user, get_redis
from app.modules.user.models import User
from app.config import get_settings

router = APIRouter()


def _scanner_key(user_id: int, scanner_id: str) -> str:
    return f"user:{user_id}:scanner:{scanner_id}"


def _scanner_list_key(user_id: int) -> str:
    return f"user:{user_id}:scanners"


@router.post("/deploy")
async def deploy_scanner(
    request: Request,
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
):
    """Deploy a new scanner instance."""
    body = await request.json()
    platform = body.get("platform", "")

    if platform not in ("kalshi", "turbine"):
        return Response(
            json.dumps({"detail": f"Unsupported scanner platform: {platform}"}),
            status_code=400, media_type="application/json",
        )

    # Verify Telegram is configured
    tg_data = await redis.get(f"user:{current_user.id}:telegram")
    if not tg_data:
        return Response(
            json.dumps({"detail": "Telegram not configured. Set up on Account page first."}),
            status_code=400, media_type="application/json",
        )

    import secrets
    scanner_id = secrets.token_hex(8)
    now = datetime.utcnow().isoformat()

    if platform == "kalshi":
        prefix = body.get("prefix", "").strip().upper()
        if not prefix or not re.match(r'^[A-Z0-9]+$', prefix):
            return Response(
                json.dumps({"detail": "Invalid market prefix. Use alphanumeric only (e.g. KXBTC)."}),
                status_code=400, media_type="application/json",
            )
        scanner_data = {
            "id": scanner_id,
            "platform": "kalshi",
            "status": "running",
            "config": {"prefix": prefix},
            "created_at": now,
        }

    elif platform == "turbine":
        wallets = body.get("wallets", [])
        if isinstance(wallets, str):
            wallets = [w.strip() for w in wallets.split(",") if w.strip()]
        if not wallets:
            return Response(
                json.dumps({"detail": "At least one wallet address is required."}),
                status_code=400, media_type="application/json",
            )
        # Basic hex address validation
        for w in wallets:
            clean = w.lower()
            if not re.match(r'^0x[a-f0-9]{40}$', clean):
                return Response(
                    json.dumps({"detail": f"Invalid wallet address: {w}"}),
                    status_code=400, media_type="application/json",
                )
        scanner_data = {
            "id": scanner_id,
            "platform": "turbine",
            "status": "running",
            "config": {"wallets": wallets},
            "created_at": now,
        }

    # Check for duplicate scanner with same config
    existing_ids = await redis.smembers(_scanner_list_key(current_user.id))
    for sid in existing_ids:
        sid_str = sid if isinstance(sid, str) else sid.decode()
        existing = await redis.get(_scanner_key(current_user.id, sid_str))
        if existing:
            existing_data = json.loads(existing)
            if existing_data.get("platform") == platform and existing_data.get("config") == scanner_data["config"]:
                return Response(
                    json.dumps({"detail": "A scanner with this configuration already exists."}),
                    status_code=409, media_type="application/json",
                )

    # Store scanner in Redis
    await redis.set(
        _scanner_key(current_user.id, scanner_id),
        json.dumps(scanner_data),
        ex=86400 * 7,  # 7 days TTL
    )

    # Add to user's scanner list
    await redis.sadd(_scanner_list_key(current_user.id), scanner_id)

    # TODO: Start Celery task for actual polling/scanning
    # For Kalshi: poll Kalshi API for new markets with prefix every ~30s
    # For Turbine: poll Turbine contract events for wallet trades every ~15s
    # When found, send Telegram notification via bot

    return scanner_data


@router.get("/list")
async def list_scanners(
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
):
    """List all active scanners for the current user."""
    scanner_ids = await redis.smembers(_scanner_list_key(current_user.id))
    scanners = []

    for sid in scanner_ids:
        sid_str = sid if isinstance(sid, str) else sid.decode()
        data = await redis.get(_scanner_key(current_user.id, sid_str))
        if data:
            scanners.append(json.loads(data))
        else:
            # Expired, remove from set
            await redis.srem(_scanner_list_key(current_user.id), sid_str)

    return {"scanners": scanners}


@router.post("/{scanner_id}/stop")
async def stop_scanner(
    scanner_id: str,
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
):
    """Stop and remove a scanner."""
    key = _scanner_key(current_user.id, scanner_id)
    data = await redis.get(key)

    if not data:
        return Response(
            json.dumps({"detail": "Scanner not found"}),
            status_code=404, media_type="application/json",
        )

    # TODO: Cancel the Celery task if running

    await redis.delete(key)
    await redis.srem(_scanner_list_key(current_user.id), scanner_id)

    return {"ok": True, "id": scanner_id}
