from __future__ import annotations

from datetime import date

from fastapi import APIRouter, Form, Request
from fastapi.responses import RedirectResponse
from app.core.http_responses import forbidden_response, not_found_response

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.services.models import ServiceTaskDocumentRequest
from app.modules.work_detail.service import assign_task_to_consultant, create_document_request, get_task_for_action, load_unified_engagement_detail, review_consultant_submission, save_task_comment, save_task_status, update_document_request

router = APIRouter(prefix="/work", tags=["unified-work-detail-ui"])


def _csrf_rejected(request: Request):
    from app.core.http_responses import forbidden_response
    return forbidden_response(request, "CSRF validation failed")



def _base_ctx(request: Request, db, user, **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),
    }
    base.update(ctx)
    return base


def _fallback_for_user(db, user) -> str:
    roles = set(get_user_roles(db, user.id))
    if "Client" in roles:
        return "/client/compliance"
    if "Consultant" in roles:
        return "/consultant/work"
    if "Partner" in roles:
        return "/partner/reviews"
    if roles.intersection({"Manager", "Branch Manager"}):
        return "/manager/work"
    return "/employee/work"


@router.get("")
def unified_work_board(request: Request):
    """Compatibility alias for the common /work route.

    Existing functionality remains in the Services Work Tracker module.
    This route only prevents stale bookmarks/tests from receiving a 404.
    """
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        return RedirectResponse(url="/services/work-tracker", status_code=303)
    finally:
        db.close()




# Phase 3 security hardening: /work/engagements is a listing alias, not a create endpoint.
# Existing engagement creation remains in the services module.
@router.post("/engagements")
def unified_engagements_post_rejected(request: Request):
    return _csrf_rejected(request)


@router.get("/engagements")
def unified_engagements_index(request: Request):
    """Compatibility alias for /work/engagements.

    Engagement listing is maintained under /services/engagements.
    """
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        return RedirectResponse(url="/services/engagements", status_code=303)
    finally:
        db.close()


@router.get("/engagements/{engagement_id}")
def unified_engagement_detail(request: Request, engagement_id: int):
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        if "Client" in set(get_user_roles(db, user.id)):
            return forbidden_response(request, "Access denied")
        detail = load_unified_engagement_detail(db, request=request, user=user, engagement_id=engagement_id)
        if not detail:
            return not_found_response(request, "Work engagement not found or access denied")
        return templates.TemplateResponse(
            "modules/work_detail/templates/work_detail/engagement_detail.html",
            _base_ctx(request, db, user, title="Work Details", **detail),
        )
    finally:
        db.close()


@router.post("/tasks/{task_id}/status")
async def unified_task_status_update(request: Request, task_id: int, csrf_token: str = Form(...), status: str = Form(...), priority: str = Form("")):
    try:
        validate_csrf(request, csrf_token)
    except PermissionError:
        return _csrf_rejected(request)
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        task, access = get_task_for_action(db, user=user, task_id=task_id)
        if not task or not access:
            return RedirectResponse(url=_fallback_for_user(db, user), status_code=303)
        if not access.can_update_tasks:
            return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?error=not_allowed", status_code=303)
        save_task_status(db, task=task, status=status, priority=priority, user_id=user.id)
        db.commit()
        return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?updated=1", status_code=303)
    except Exception:
        db.rollback()
        raise
    finally:
        db.close()


@router.post("/tasks/{task_id}/comment")
async def unified_task_comment_add(
    request: Request,
    task_id: int,
    csrf_token: str = Form(...),
    comment_type: str = Form("internal_note"),
    visibility: str = Form("internal"),
    message: str = Form(""),
):
    try:
        validate_csrf(request, csrf_token)
    except PermissionError:
        return _csrf_rejected(request)
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        task, access = get_task_for_action(db, user=user, task_id=task_id)
        if not task or not access:
            return RedirectResponse(url=_fallback_for_user(db, user), status_code=303)
        if not access.can_comment:
            return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?error=comment_not_allowed", status_code=303)
        ok = save_task_comment(db, task=task, access=access, comment_type=comment_type, visibility=visibility, message=message, user_id=user.id)
        if ok:
            db.commit()
            return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?comment=sent", status_code=303)
        db.rollback()
        return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?error=empty_comment", status_code=303)
    except Exception:
        db.rollback()
        raise
    finally:
        db.close()


@router.post("/tasks/{task_id}/document-requests")
async def unified_document_request_add(request: Request, task_id: int, csrf_token: str = Form(...), title: str = Form(...), description: str = Form(""), requested_from: str = Form("client_and_consultant"), due_date: str = Form(""), request_type: str = Form("document")):
    try:
        validate_csrf(request, csrf_token)
    except PermissionError:
        return _csrf_rejected(request)
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        task, access = get_task_for_action(db, user=user, task_id=task_id)
        if not task or not access:
            return RedirectResponse(url=_fallback_for_user(db, user), status_code=303)
        parsed_due = date.fromisoformat(due_date) if due_date else None
        row = create_document_request(db, task=task, access=access, title=title, description=description, requested_from=requested_from, due_date=parsed_due, request_type=request_type, user_id=user.id)
        if not row:
            return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?error=request_not_allowed", status_code=303)
        db.commit()
        return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?request=created", status_code=303)
    except Exception:
        db.rollback(); raise
    finally:
        db.close()


@router.post("/document-requests/{request_id}/status")
async def unified_document_request_status(request: Request, request_id: int, csrf_token: str = Form(...), status: str = Form(...), response_note: str = Form("")):
    try:
        validate_csrf(request, csrf_token)
    except PermissionError:
        return _csrf_rejected(request)
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        row = db.get(ServiceTaskDocumentRequest, request_id)
        if not row or not row.is_active:
            return not_found_response(request, "Document request not found")
        task, access = get_task_for_action(db, user=user, task_id=row.task_instance_id)
        if not task or not access or not update_document_request(db, request_row=row, access=access, status=status, response_note=response_note, user_id=user.id):
            return RedirectResponse(url=_fallback_for_user(db, user), status_code=303)
        db.commit()
        return RedirectResponse(url=f"/work/engagements/{row.subscription_id}?request=updated", status_code=303)
    except Exception:
        db.rollback(); raise
    finally:
        db.close()


@router.post("/tasks/{task_id}/consultant-assignment")
async def unified_consultant_assignment_update(request: Request, task_id: int, csrf_token: str = Form(...), consultant_id: str = Form(""), consultant_due_date: str = Form("")):
    try:
        validate_csrf(request, csrf_token)
    except PermissionError:
        return _csrf_rejected(request)
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        task, access = get_task_for_action(db, user=user, task_id=task_id)
        if not task or not access:
            return RedirectResponse(url=_fallback_for_user(db, user), status_code=303)
        parsed_consultant_id = int(consultant_id) if consultant_id.strip() else None
        parsed_due = date.fromisoformat(consultant_due_date) if consultant_due_date else None
        if not assign_task_to_consultant(db, task=task, access=access, consultant_id=parsed_consultant_id, due_date=parsed_due, user_id=user.id):
            return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?error=consultant_assignment_not_allowed", status_code=303)
        db.commit()
        return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?consultant_assignment=updated", status_code=303)
    except (ValueError, TypeError):
        db.rollback()
        return RedirectResponse(url=f"/work/engagements/{task.subscription_id if 'task' in locals() and task else ''}?error=invalid_consultant_assignment", status_code=303)
    except Exception:
        db.rollback(); raise
    finally:
        db.close()


@router.post("/tasks/{task_id}/consultant-review")
async def unified_consultant_submission_review(request: Request, task_id: int, csrf_token: str = Form(...), action: str = Form(...), note: str = Form("")):
    try:
        validate_csrf(request, csrf_token)
    except PermissionError:
        return _csrf_rejected(request)
    db = CommonSessionLocal()
    try:
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse(url="/login", status_code=303)
        task, access = get_task_for_action(db, user=user, task_id=task_id)
        if not task or not access:
            return RedirectResponse(url=_fallback_for_user(db, user), status_code=303)
        if not review_consultant_submission(db, task=task, access=access, action=action, note=note, user_id=user.id):
            return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?error=consultant_review_not_allowed", status_code=303)
        db.commit()
        return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?consultant_review=updated", status_code=303)
    except Exception:
        db.rollback(); raise
    finally:
        db.close()
