"""
Middleware Admin API Endpoints for BreakPilot

Provides admin functionality for managing middleware configurations:
- View and update middleware settings
- Rate limiting IP whitelist/blacklist
- View middleware events/statistics
"""

import os
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, Field

# Database connection
import asyncpg

# Session middleware for authentication
from session import require_permission, Session


router = APIRouter(prefix="/api/admin/middleware", tags=["middleware-admin"])

# Database URL
DATABASE_URL = os.getenv(
    "DATABASE_URL",
    "postgresql://breakpilot:breakpilot@localhost:5432/breakpilot_dev"
)

# Lazy database pool
_db_pool: Optional[asyncpg.Pool] = None


async def get_db_pool() -> asyncpg.Pool:
    """Get or create database connection pool."""
    global _db_pool
    if _db_pool is None:
        _db_pool = await asyncpg.create_pool(DATABASE_URL, min_size=2, max_size=10)
    return _db_pool


# ==============================================
# Request/Response Models
# ==============================================


class MiddlewareConfigResponse(BaseModel):
    """Response model for middleware configuration."""
    id: str
    middleware_name: str
    enabled: bool
    config: Dict[str, Any]
    updated_at: Optional[datetime] = None


class MiddlewareConfigUpdateRequest(BaseModel):
    """Request model for updating middleware configuration."""
    enabled: Optional[bool] = None
    config: Optional[Dict[str, Any]] = None


class RateLimitIPRequest(BaseModel):
    """Request model for adding IP to whitelist/blacklist."""
    ip_address: str
    list_type: str = Field(..., pattern="^(whitelist|blacklist)$")
    reason: Optional[str] = None
    expires_at: Optional[datetime] = None


class RateLimitIPResponse(BaseModel):
    """Response model for rate limit IP entry."""
    id: str
    ip_address: str
    list_type: str
    reason: Optional[str] = None
    expires_at: Optional[datetime] = None
    created_at: datetime


class MiddlewareEventResponse(BaseModel):
    """Response model for middleware event."""
    id: str
    middleware_name: str
    event_type: str
    ip_address: Optional[str] = None
    user_id: Optional[str] = None
    request_path: Optional[str] = None
    request_method: Optional[str] = None
    details: Optional[Dict[str, Any]] = None
    created_at: datetime


class MiddlewareStatsResponse(BaseModel):
    """Response model for middleware statistics."""
    middleware_name: str
    total_events: int
    events_last_hour: int
    events_last_24h: int
    top_event_types: List[Dict[str, Any]]
    top_ips: List[Dict[str, Any]]


# ==============================================
# Middleware Configuration Endpoints
# ==============================================


@router.get("", response_model=List[MiddlewareConfigResponse])
async def list_middleware_configs(
    session: Session = Depends(require_permission("settings:read")),
):
    """
    List all middleware configurations.

    Requires: settings:read permission
    """
    pool = await get_db_pool()

    rows = await pool.fetch("""
        SELECT id, middleware_name, enabled, config, updated_at
        FROM middleware_config
        ORDER BY middleware_name
    """)

    return [
        MiddlewareConfigResponse(
            id=str(row["id"]),
            middleware_name=row["middleware_name"],
            enabled=row["enabled"],
            config=row["config"] or {},
            updated_at=row["updated_at"],
        )
        for row in rows
    ]


@router.get("/{name}", response_model=MiddlewareConfigResponse)
async def get_middleware_config(
    name: str,
    session: Session = Depends(require_permission("settings:read")),
):
    """
    Get configuration for a specific middleware.

    Requires: settings:read permission
    """
    pool = await get_db_pool()

    row = await pool.fetchrow("""
        SELECT id, middleware_name, enabled, config, updated_at
        FROM middleware_config
        WHERE middleware_name = $1
    """, name)

    if not row:
        raise HTTPException(status_code=404, detail=f"Middleware '{name}' not found")

    return MiddlewareConfigResponse(
        id=str(row["id"]),
        middleware_name=row["middleware_name"],
        enabled=row["enabled"],
        config=row["config"] or {},
        updated_at=row["updated_at"],
    )


@router.put("/{name}", response_model=MiddlewareConfigResponse)
async def update_middleware_config(
    name: str,
    data: MiddlewareConfigUpdateRequest,
    session: Session = Depends(require_permission("settings:write")),
):
    """
    Update configuration for a specific middleware.

    Requires: settings:write permission
    """
    pool = await get_db_pool()

    # Build update query dynamically
    updates = []
    params = [name]
    param_idx = 2

    if data.enabled is not None:
        updates.append(f"enabled = ${param_idx}")
        params.append(data.enabled)
        param_idx += 1

    if data.config is not None:
        updates.append(f"config = ${param_idx}")
        params.append(data.config)
        param_idx += 1

    if not updates:
        raise HTTPException(status_code=400, detail="No fields to update")

    updates.append("updated_at = NOW()")
    updates.append(f"updated_by = ${param_idx}")
    params.append(session.user_id)

    query = f"""
        UPDATE middleware_config
        SET {", ".join(updates)}
        WHERE middleware_name = $1
        RETURNING id, middleware_name, enabled, config, updated_at
    """

    row = await pool.fetchrow(query, *params)

    if not row:
        raise HTTPException(status_code=404, detail=f"Middleware '{name}' not found")

    # Log the configuration change
    await pool.execute("""
        INSERT INTO middleware_events (middleware_name, event_type, user_id, details)
        VALUES ($1, 'config_changed', $2, $3)
    """, name, session.user_id, {"changes": data.dict(exclude_none=True)})

    return MiddlewareConfigResponse(
        id=str(row["id"]),
        middleware_name=row["middleware_name"],
        enabled=row["enabled"],
        config=row["config"] or {},
        updated_at=row["updated_at"],
    )


# ==============================================
# Rate Limiting IP Management
# ==============================================


@router.get("/rate-limit/ip-list", response_model=List[RateLimitIPResponse])
async def list_rate_limit_ips(
    list_type: Optional[str] = Query(None, pattern="^(whitelist|blacklist)$"),
    session: Session = Depends(require_permission("settings:read")),
):
    """
    List all IPs in whitelist/blacklist.

    Requires: settings:read permission
    """
    pool = await get_db_pool()

    if list_type:
        rows = await pool.fetch("""
            SELECT id, ip_address::text, list_type, reason, expires_at, created_at
            FROM rate_limit_ip_list
            WHERE list_type = $1
            ORDER BY created_at DESC
        """, list_type)
    else:
        rows = await pool.fetch("""
            SELECT id, ip_address::text, list_type, reason, expires_at, created_at
            FROM rate_limit_ip_list
            ORDER BY list_type, created_at DESC
        """)

    return [
        RateLimitIPResponse(
            id=str(row["id"]),
            ip_address=row["ip_address"],
            list_type=row["list_type"],
            reason=row["reason"],
            expires_at=row["expires_at"],
            created_at=row["created_at"],
        )
        for row in rows
    ]


@router.post("/rate-limit/ip-list", response_model=RateLimitIPResponse, status_code=201)
async def add_rate_limit_ip(
    data: RateLimitIPRequest,
    session: Session = Depends(require_permission("settings:write")),
):
    """
    Add IP to whitelist or blacklist.

    Requires: settings:write permission
    """
    pool = await get_db_pool()

    try:
        row = await pool.fetchrow("""
            INSERT INTO rate_limit_ip_list (ip_address, list_type, reason, expires_at, created_by)
            VALUES ($1::inet, $2, $3, $4, $5)
            RETURNING id, ip_address::text, list_type, reason, expires_at, created_at
        """, data.ip_address, data.list_type, data.reason, data.expires_at, session.user_id)
    except asyncpg.UniqueViolationError:
        raise HTTPException(
            status_code=409,
            detail=f"IP {data.ip_address} already exists in {data.list_type}"
        )

    # Log the event
    await pool.execute("""
        INSERT INTO middleware_events (middleware_name, event_type, ip_address, user_id, details)
        VALUES ('rate_limiter', $1, $2::inet, $3, $4)
    """, f"ip_{data.list_type}_add", data.ip_address, session.user_id,
        {"reason": data.reason})

    return RateLimitIPResponse(
        id=str(row["id"]),
        ip_address=row["ip_address"],
        list_type=row["list_type"],
        reason=row["reason"],
        expires_at=row["expires_at"],
        created_at=row["created_at"],
    )


@router.delete("/rate-limit/ip-list/{ip_id}")
async def remove_rate_limit_ip(
    ip_id: str,
    session: Session = Depends(require_permission("settings:write")),
):
    """
    Remove IP from whitelist/blacklist.

    Requires: settings:write permission
    """
    pool = await get_db_pool()

    # Get the entry first for logging
    row = await pool.fetchrow("""
        SELECT ip_address::text, list_type FROM rate_limit_ip_list WHERE id = $1
    """, ip_id)

    if not row:
        raise HTTPException(status_code=404, detail="IP entry not found")

    await pool.execute("""
        DELETE FROM rate_limit_ip_list WHERE id = $1
    """, ip_id)

    # Log the event
    await pool.execute("""
        INSERT INTO middleware_events (middleware_name, event_type, ip_address, user_id, details)
        VALUES ('rate_limiter', $1, $2::inet, $3, $4)
    """, f"ip_{row['list_type']}_remove", row["ip_address"], session.user_id, {})

    return {"message": "IP removed successfully"}


# ==============================================
# Middleware Events & Statistics
# ==============================================


@router.get("/events", response_model=List[MiddlewareEventResponse])
async def list_middleware_events(
    middleware_name: Optional[str] = None,
    event_type: Optional[str] = None,
    limit: int = Query(100, le=1000),
    offset: int = 0,
    session: Session = Depends(require_permission("audit:read")),
):
    """
    List middleware events (rate limit triggers, config changes, etc.).

    Requires: audit:read permission
    """
    pool = await get_db_pool()

    conditions = []
    params = []
    param_idx = 1

    if middleware_name:
        conditions.append(f"middleware_name = ${param_idx}")
        params.append(middleware_name)
        param_idx += 1

    if event_type:
        conditions.append(f"event_type = ${param_idx}")
        params.append(event_type)
        param_idx += 1

    where_clause = f"WHERE {' AND '.join(conditions)}" if conditions else ""

    params.extend([limit, offset])
    query = f"""
        SELECT id, middleware_name, event_type, ip_address::text, user_id::text,
               request_path, request_method, details, created_at
        FROM middleware_events
        {where_clause}
        ORDER BY created_at DESC
        LIMIT ${param_idx} OFFSET ${param_idx + 1}
    """

    rows = await pool.fetch(query, *params)

    return [
        MiddlewareEventResponse(
            id=str(row["id"]),
            middleware_name=row["middleware_name"],
            event_type=row["event_type"],
            ip_address=row["ip_address"],
            user_id=row["user_id"],
            request_path=row["request_path"],
            request_method=row["request_method"],
            details=row["details"],
            created_at=row["created_at"],
        )
        for row in rows
    ]


@router.get("/stats", response_model=List[MiddlewareStatsResponse])
async def get_middleware_stats(
    session: Session = Depends(require_permission("settings:read")),
):
    """
    Get statistics for all middlewares.

    Requires: settings:read permission
    """
    pool = await get_db_pool()

    stats = []
    middlewares = ["request_id", "security_headers", "cors", "rate_limiter", "pii_redactor", "input_gate"]

    for mw in middlewares:
        # Get event counts
        counts = await pool.fetchrow("""
            SELECT
                COUNT(*) as total,
                COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '1 hour') as last_hour,
                COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '24 hours') as last_24h
            FROM middleware_events
            WHERE middleware_name = $1
        """, mw)

        # Get top event types
        top_events = await pool.fetch("""
            SELECT event_type, COUNT(*) as count
            FROM middleware_events
            WHERE middleware_name = $1 AND created_at > NOW() - INTERVAL '24 hours'
            GROUP BY event_type
            ORDER BY count DESC
            LIMIT 5
        """, mw)

        # Get top IPs (for rate limiter)
        top_ips = await pool.fetch("""
            SELECT ip_address::text, COUNT(*) as count
            FROM middleware_events
            WHERE middleware_name = $1
              AND ip_address IS NOT NULL
              AND created_at > NOW() - INTERVAL '24 hours'
            GROUP BY ip_address
            ORDER BY count DESC
            LIMIT 5
        """, mw)

        stats.append(MiddlewareStatsResponse(
            middleware_name=mw,
            total_events=counts["total"] or 0,
            events_last_hour=counts["last_hour"] or 0,
            events_last_24h=counts["last_24h"] or 0,
            top_event_types=[
                {"event_type": r["event_type"], "count": r["count"]}
                for r in top_events
            ],
            top_ips=[
                {"ip_address": r["ip_address"], "count": r["count"]}
                for r in top_ips
            ],
        ))

    return stats


@router.get("/stats/{name}", response_model=MiddlewareStatsResponse)
async def get_middleware_stats_by_name(
    name: str,
    session: Session = Depends(require_permission("settings:read")),
):
    """
    Get statistics for a specific middleware.

    Requires: settings:read permission
    """
    pool = await get_db_pool()

    # Get event counts
    counts = await pool.fetchrow("""
        SELECT
            COUNT(*) as total,
            COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '1 hour') as last_hour,
            COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '24 hours') as last_24h
        FROM middleware_events
        WHERE middleware_name = $1
    """, name)

    # Get top event types
    top_events = await pool.fetch("""
        SELECT event_type, COUNT(*) as count
        FROM middleware_events
        WHERE middleware_name = $1 AND created_at > NOW() - INTERVAL '24 hours'
        GROUP BY event_type
        ORDER BY count DESC
        LIMIT 10
    """, name)

    # Get top IPs
    top_ips = await pool.fetch("""
        SELECT ip_address::text, COUNT(*) as count
        FROM middleware_events
        WHERE middleware_name = $1
          AND ip_address IS NOT NULL
          AND created_at > NOW() - INTERVAL '24 hours'
        GROUP BY ip_address
        ORDER BY count DESC
        LIMIT 10
    """, name)

    return MiddlewareStatsResponse(
        middleware_name=name,
        total_events=counts["total"] or 0,
        events_last_hour=counts["last_hour"] or 0,
        events_last_24h=counts["last_24h"] or 0,
        top_event_types=[
            {"event_type": r["event_type"], "count": r["count"]}
            for r in top_events
        ],
        top_ips=[
            {"ip_address": r["ip_address"], "count": r["count"]}
            for r in top_ips
        ],
    )
