from __future__ import annotations

from fastapi import APIRouter, Form, Request
from fastapi.responses import RedirectResponse

from app.core.db.common import CommonSessionLocal
from app.core.security.csrf import get_or_create_csrf_token, validate_csrf
from app.core.security.session_auth import get_current_user
from app.core.templating import templates
from app.modules.core.rbac.deps import get_user_permissions, get_user_roles
from app.modules.core.rbac.permission_guard import require_permission
from app.modules.services.execution import (
    TASK_PRIORITIES,
    TASK_STATUSES,
    apply_task_update,
    dashboard_stats,
    generate_tasks_for_subscription,
    get_subscription_for_execution,
    get_task,
    list_assignees_for_execution,
    list_subscription_execution_payload,
    list_tasks_payload,
)

router = APIRouter(prefix="/services/execution", tags=["services-execution-ui"])


def _base_ctx(request: Request, user, db, **ctx):
    base = {
        "request": request,
        "current_user": user,
        "current_user_roles": get_user_roles(db, user.id),
        "current_user_permissions": get_user_permissions(db, user.id),
        "csrf_token": get_or_create_csrf_token(request),
        "task_statuses": TASK_STATUSES,
        "task_priorities": TASK_PRIORITIES,
    }
    base.update(ctx)
    return base


def _render(request: Request, template: str, db, user, **ctx):
    return templates.TemplateResponse(template, _base_ctx(request, user, db, **ctx))


def _redirect_denied():
    from app.core.http_responses import ui_access_denied
    return ui_access_denied()


def _has_perm(db, user, code: str) -> bool:
    try:
        require_permission(db, user, code)
        return True
    except Exception:
        return False


def _active_tenant_id(request: Request, user) -> int:
    return int(
        request.session.get("active_tenant_id")
        or request.session.get("selected_tenant_id")
        or request.session.get("tenant_id")
        or user.tenant_id
    )


def _active_branch_id(request: Request, user, db) -> int | None:
    value = request.session.get("active_branch_id")
    if value in (None, "", 0, "0"):
        if _has_perm(db, user, "clients.cross_branch"):
            return None
        return int(getattr(user, "branch_id", 0) or 0) or None
    return int(value)


def _assigned_user_filter(db, user) -> int | None:
    # Partner/Staff style users with own-only permission see only their assigned tasks.
    return int(user.id) if _has_perm(db, user, "clients.view.own_only") else None


def _can_manage_execution(db, user) -> bool:
    return _has_perm(db, user, "service_tasks.edit") or _has_perm(db, user, "service_tasks.create")


@router.get("")
def execution_dashboard(request: Request, q: str = "", status: str = ""):
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        try:
            require_permission(db, user, "service_tasks.view")
        except Exception:
            return _redirect_denied()

        tenant_id = _active_tenant_id(request, user)
        branch_id = _active_branch_id(request, user, db)
        assigned_to_user_id = _assigned_user_filter(db, user)
        stats = dashboard_stats(db, tenant_id=tenant_id, branch_id=branch_id, assigned_to_user_id=assigned_to_user_id)
        tasks = list_tasks_payload(
            db,
            tenant_id=tenant_id,
            branch_id=branch_id,
            assigned_to_user_id=assigned_to_user_id,
            status=status,
            q=q,
        )
        return _render(
            request,
            "modules/services/templates/services/execution/dashboard.html",
            db,
            user,
            title="Service Execution Dashboard",
            stats=stats,
            tasks=tasks,
            q=q,
            status=status,
            can_manage=_can_manage_execution(db, user),
        )
    finally:
        db.close()


@router.get("/subscriptions")
def subscription_execution_list(request: Request, q: str = ""):
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        try:
            require_permission(db, user, "clients.view")
        except Exception:
            return _redirect_denied()

        tenant_id = _active_tenant_id(request, user)
        branch_id = _active_branch_id(request, user, db)
        rows = list_subscription_execution_payload(db, tenant_id=tenant_id, branch_id=branch_id, q=q)
        return _render(
            request,
            "modules/services/templates/services/execution/subscriptions.html",
            db,
            user,
            title="Generate Service Tasks",
            rows=rows,
            q=q,
            can_generate=_has_perm(db, user, "service_tasks.create"),
        )
    finally:
        db.close()


@router.post("/subscriptions/{subscription_id}/generate")
def generate_subscription_tasks(request: Request, subscription_id: int, csrf_token: str = Form(...)):
    validate_csrf(request, csrf_token)
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        try:
            require_permission(db, user, "service_tasks.create")
        except Exception:
            return _redirect_denied()

        tenant_id = _active_tenant_id(request, user)
        subscription = get_subscription_for_execution(db, tenant_id=tenant_id, subscription_id=subscription_id)
        if not subscription or not subscription.is_active or subscription.status != "active":
            return RedirectResponse(url="/services/execution/subscriptions", status_code=303)

        generate_tasks_for_subscription(db, subscription=subscription, user_id=user.id)
        db.commit()
        return RedirectResponse(url="/services/execution", status_code=303)
    finally:
        db.close()


@router.get("/tasks/{task_id}/edit")
def task_edit_page(request: Request, task_id: int):
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        try:
            require_permission(db, user, "service_tasks.view")
        except Exception:
            return _redirect_denied()

        tenant_id = _active_tenant_id(request, user)
        task = get_task(db, tenant_id=tenant_id, task_id=task_id)
        if not task:
            return RedirectResponse(url="/services/execution", status_code=303)

        own_only_user_id = _assigned_user_filter(db, user)
        if own_only_user_id and task.assigned_to_user_id != own_only_user_id:
            return _redirect_denied()

        branch_id = _active_branch_id(request, user, db)
        assignees = list_assignees_for_execution(db, tenant_id=tenant_id, branch_id=branch_id)
        return _render(
            request,
            "modules/services/templates/services/execution/task_form.html",
            db,
            user,
            title="Update Service Task",
            task=task,
            assignees=assignees,
            can_edit=_has_perm(db, user, "service_tasks.edit"),
        )
    finally:
        db.close()


@router.post("/tasks/{task_id}/edit")
def task_edit_submit(
    request: Request,
    task_id: int,
    status: str = Form("pending"),
    priority: str = Form("normal"),
    assigned_to_user_id: str = Form(""),
    remarks: str = Form(""),
    is_active: str | None = Form(None),
    csrf_token: str = Form(...),
):
    validate_csrf(request, csrf_token)
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        try:
            require_permission(db, user, "service_tasks.edit")
        except Exception:
            return _redirect_denied()

        tenant_id = _active_tenant_id(request, user)
        task = get_task(db, tenant_id=tenant_id, task_id=task_id)
        if not task:
            return RedirectResponse(url="/services/execution", status_code=303)

        own_only_user_id = _assigned_user_filter(db, user)
        if own_only_user_id and task.assigned_to_user_id != own_only_user_id:
            return _redirect_denied()

        apply_task_update(
            task,
            status=status,
            priority=priority,
            assigned_to_user_id=int(assigned_to_user_id) if assigned_to_user_id.strip() else None,
            remarks=remarks,
            is_active=is_active is not None,
            user_id=user.id,
        )
        db.commit()
        return RedirectResponse(url="/services/execution", status_code=303)
    finally:
        db.close()
