"""YakPanel - Firewall API"""
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from pydantic import BaseModel

from app.core.database import get_db
from app.core.utils import exec_shell_sync
from app.api.auth import get_current_user
from app.models.user import User
from app.models.firewall import FirewallRule

router = APIRouter(prefix="/firewall", tags=["firewall"])


class CreateFirewallRuleRequest(BaseModel):
    port: str
    protocol: str = "tcp"
    action: str = "accept"
    ps: str = ""


@router.get("/list")
async def firewall_list(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """List firewall rules"""
    result = await db.execute(select(FirewallRule).order_by(FirewallRule.id))
    rows = result.scalars().all()
    return [{"id": r.id, "port": r.port, "protocol": r.protocol, "action": r.action, "ps": r.ps} for r in rows]


@router.post("/create")
async def firewall_create(
    body: CreateFirewallRuleRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Add firewall rule (stored in panel; use Apply to UFW to sync)"""
    if not body.port or len(body.port) > 32:
        raise HTTPException(status_code=400, detail="Invalid port")
    rule = FirewallRule(port=body.port, protocol=body.protocol, action=body.action, ps=body.ps)
    db.add(rule)
    await db.commit()
    return {"status": True, "msg": "Rule added", "id": rule.id}


@router.delete("/{rule_id}")
async def firewall_delete(
    rule_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Delete firewall rule"""
    result = await db.execute(select(FirewallRule).where(FirewallRule.id == rule_id))
    rule = result.scalar_one_or_none()
    if not rule:
        raise HTTPException(status_code=404, detail="Rule not found")
    await db.delete(rule)
    await db.commit()
    return {"status": True, "msg": "Rule deleted"}


@router.post("/apply")
async def firewall_apply(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Apply firewall rules to ufw (runs ufw allow/deny for each rule)"""
    result = await db.execute(select(FirewallRule).order_by(FirewallRule.id))
    rules = result.scalars().all()
    errors = []
    for r in rules:
        port_proto = f"{r.port}/{r.protocol}"
        action = "allow" if r.action == "accept" else "deny"
        cmd = f"ufw {action} {port_proto}"
        out, err = exec_shell_sync(cmd, timeout=10)
        if err and "error" in err.lower() and "already" not in err.lower():
            errors.append(f"{port_proto}: {err.strip()}")
    if errors:
        raise HTTPException(status_code=500, detail="; ".join(errors))
    return {"status": True, "msg": "Rules applied", "count": len(rules)}
