"""
Task Management API
Handles TaskOrchestrator task lifecycle

Endpoints:
- POST   /api/v1/tasks                 # Task erstellen
- GET    /api/v1/tasks/{id}            # Task Status
- PUT    /api/v1/tasks/{id}/transition # Status aendern
- DELETE /api/v1/tasks/{id}            # Task loeschen
"""
import structlog
from fastapi import APIRouter, HTTPException, Request
from typing import Optional
from datetime import datetime

from config import settings
from models.task import (
    Task,
    TaskCreate,
    TaskResponse,
    TaskTransition,
    TaskState,
    TaskType,
    is_valid_transition,
)

logger = structlog.get_logger(__name__)

router = APIRouter()

# In-memory task store (will be replaced with Valkey in production)
_tasks: dict[str, Task] = {}


async def get_task(task_id: str) -> Task:
    """Get task by ID or raise 404."""
    task = _tasks.get(task_id)
    if not task:
        raise HTTPException(status_code=404, detail="Task not found")
    return task


@router.post("", response_model=TaskResponse)
async def create_task(request: Request, task_data: TaskCreate):
    """
    Create a new task.

    The task will be queued for processing by TaskOrchestrator.
    Intent text is encrypted before storage.
    """
    logger.info(
        "Creating task",
        session_id=task_data.session_id[:8],
        task_type=task_data.type.value,
    )

    # Get encryption service
    encryption = request.app.state.encryption

    # Get session to validate and get namespace
    from api.sessions import _sessions
    session = _sessions.get(task_data.session_id)
    if not session:
        raise HTTPException(status_code=404, detail="Session not found")

    # Encrypt intent text if encryption is enabled
    encrypted_intent = task_data.intent_text
    if settings.encryption_enabled:
        encrypted_intent = encryption.encrypt_content(
            task_data.intent_text,
            session.namespace_id,
        )

    # Encrypt any PII in parameters
    encrypted_params = {}
    pii_fields = ["student_name", "class_name", "parent_name", "content"]
    for key, value in task_data.parameters.items():
        if key in pii_fields and settings.encryption_enabled:
            encrypted_params[key] = encryption.encrypt_content(
                str(value),
                session.namespace_id,
            )
        else:
            encrypted_params[key] = value

    # Create task
    task = Task(
        session_id=task_data.session_id,
        namespace_id=session.namespace_id,
        type=task_data.type,
        intent_text=encrypted_intent,
        parameters=encrypted_params,
    )

    # Store task
    _tasks[task.id] = task

    # Add to session's pending tasks
    session.pending_tasks.append(task.id)

    # Queue task for processing
    orchestrator = request.app.state.orchestrator
    await orchestrator.queue_task(task)

    logger.info(
        "Task created",
        task_id=task.id[:8],
        session_id=task_data.session_id[:8],
        task_type=task_data.type.value,
    )

    return TaskResponse(
        id=task.id,
        session_id=task.session_id,
        type=task.type,
        state=task.state,
        created_at=task.created_at,
        updated_at=task.updated_at,
        result_available=False,
    )


@router.get("/{task_id}", response_model=TaskResponse)
async def get_task_status(task_id: str):
    """
    Get task status.

    Returns current state and whether results are available.
    """
    task = await get_task(task_id)

    return TaskResponse(
        id=task.id,
        session_id=task.session_id,
        type=task.type,
        state=task.state,
        created_at=task.created_at,
        updated_at=task.updated_at,
        result_available=task.result_ref is not None,
        error_message=task.error_message,
    )


@router.put("/{task_id}/transition", response_model=TaskResponse)
async def transition_task(task_id: str, transition: TaskTransition):
    """
    Transition task to a new state.

    Only valid transitions are allowed according to the state machine.
    """
    task = await get_task(task_id)

    # Validate transition
    if not is_valid_transition(task.state, transition.new_state):
        raise HTTPException(
            status_code=400,
            detail=f"Invalid transition from {task.state.value} to {transition.new_state.value}"
        )

    logger.info(
        "Transitioning task",
        task_id=task_id[:8],
        from_state=task.state.value,
        to_state=transition.new_state.value,
        reason=transition.reason,
    )

    # Apply transition
    task.transition_to(transition.new_state, transition.reason)

    # If approved, execute the task
    if transition.new_state == TaskState.APPROVED:
        from services.task_orchestrator import TaskOrchestrator
        orchestrator = TaskOrchestrator()
        await orchestrator.execute_task(task)

    return TaskResponse(
        id=task.id,
        session_id=task.session_id,
        type=task.type,
        state=task.state,
        created_at=task.created_at,
        updated_at=task.updated_at,
        result_available=task.result_ref is not None,
        error_message=task.error_message,
    )


@router.delete("/{task_id}")
async def delete_task(task_id: str):
    """
    Delete a task.

    Only allowed for tasks in DRAFT, COMPLETED, or EXPIRED state.
    """
    task = await get_task(task_id)

    # Check if deletion is allowed
    if task.state not in [TaskState.DRAFT, TaskState.COMPLETED, TaskState.EXPIRED, TaskState.REJECTED]:
        raise HTTPException(
            status_code=400,
            detail=f"Cannot delete task in {task.state.value} state"
        )

    logger.info(
        "Deleting task",
        task_id=task_id[:8],
        state=task.state.value,
    )

    # Remove from session's pending tasks
    from api.sessions import _sessions
    session = _sessions.get(task.session_id)
    if session and task_id in session.pending_tasks:
        session.pending_tasks.remove(task_id)

    # Delete task
    del _tasks[task_id]

    return {"status": "deleted", "task_id": task_id}


@router.get("/{task_id}/result")
async def get_task_result(task_id: str, request: Request):
    """
    Get task result.

    Result is decrypted using the session's namespace key.
    Only available for completed tasks.
    """
    task = await get_task(task_id)

    if task.state != TaskState.COMPLETED:
        raise HTTPException(
            status_code=400,
            detail=f"Task is in {task.state.value} state, not completed"
        )

    if not task.result_ref:
        raise HTTPException(
            status_code=404,
            detail="No result available for this task"
        )

    # Get encryption service to decrypt result
    encryption = request.app.state.encryption

    # Decrypt result reference
    if settings.encryption_enabled:
        result = encryption.decrypt_content(
            task.result_ref,
            task.namespace_id,
        )
    else:
        result = task.result_ref

    return {
        "task_id": task_id,
        "type": task.type.value,
        "result": result,
        "completed_at": task.completed_at.isoformat() if task.completed_at else None,
    }
