"""Action rule management API routes."""

import logging

from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel
from sqlmodel import select
from sqlmodel.ext.asyncio.session import AsyncSession

from ..auth.dependencies import get_current_user
from ..database.engine import get_session
from ..database.models import Action, ActionRule, User
from .helpers import get_owned_entity

_LOGGER = logging.getLogger(__name__)

router = APIRouter(prefix="/api/actions", tags=["action-rules"])


# ---------------------------------------------------------------------------
# Request schemas
# ---------------------------------------------------------------------------


class ActionRuleCreate(BaseModel):
    name: str = ""
    rule_config: dict = {}
    enabled: bool = True
    order: int = 0


class ActionRuleUpdate(BaseModel):
    name: str | None = None
    rule_config: dict | None = None
    enabled: bool | None = None
    order: int | None = None


class ReorderBody(BaseModel):
    rule_ids: list[int]


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _rule_response(rule: ActionRule) -> dict:
    return {
        "id": rule.id,
        "action_id": rule.action_id,
        "name": rule.name,
        "rule_config": rule.rule_config,
        "enabled": rule.enabled,
        "order": rule.order,
        "created_at": rule.created_at.isoformat() if rule.created_at else None,
    }


async def _get_user_action(
    session: AsyncSession, action_id: int, user: User
) -> Action:
    return await get_owned_entity(
        session, Action, action_id, user.id, not_found_msg="Action not found",
    )


# ---------------------------------------------------------------------------
# Routes
# ---------------------------------------------------------------------------


@router.get("/{action_id}/rules")
async def list_rules(
    action_id: int,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    await _get_user_action(session, action_id, user)
    result = await session.exec(
        select(ActionRule)
        .where(ActionRule.action_id == action_id)
        .order_by(ActionRule.order)
    )
    return [_rule_response(r) for r in result.all()]


@router.post("/{action_id}/rules", status_code=status.HTTP_201_CREATED)
async def create_rule(
    action_id: int,
    body: ActionRuleCreate,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    await _get_user_action(session, action_id, user)
    rule = ActionRule(action_id=action_id, **body.model_dump())
    session.add(rule)
    await session.commit()
    await session.refresh(rule)
    return _rule_response(rule)


@router.put("/{action_id}/rules/reorder")
async def reorder_rules(
    action_id: int,
    body: ReorderBody,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    await _get_user_action(session, action_id, user)
    result = await session.exec(
        select(ActionRule).where(ActionRule.action_id == action_id)
    )
    rules_by_id = {r.id: r for r in result.all()}

    for idx, rule_id in enumerate(body.rule_ids):
        rule = rules_by_id.get(rule_id)
        if rule:
            rule.order = idx
            session.add(rule)

    await session.commit()
    return {"status": "ok"}


@router.put("/{action_id}/rules/{rule_id}")
async def update_rule(
    action_id: int,
    rule_id: int,
    body: ActionRuleUpdate,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    await _get_user_action(session, action_id, user)
    rule = await session.get(ActionRule, rule_id)
    if not rule or rule.action_id != action_id:
        raise HTTPException(status_code=404, detail="Rule not found")

    updates = body.model_dump(exclude_unset=True)
    for key, value in updates.items():
        setattr(rule, key, value)
    session.add(rule)
    await session.commit()
    await session.refresh(rule)
    return _rule_response(rule)


@router.delete(
    "/{action_id}/rules/{rule_id}", status_code=status.HTTP_204_NO_CONTENT
)
async def delete_rule(
    action_id: int,
    rule_id: int,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    await _get_user_action(session, action_id, user)
    rule = await session.get(ActionRule, rule_id)
    if not rule or rule.action_id != action_id:
        raise HTTPException(status_code=404, detail="Rule not found")
    await session.delete(rule)
    await session.commit()
