from __future__ import annotations

from backend.app.api.errors import AppError
from backend.app.api.schemas import TaskDetailResponse, TaskListItem, TaskListResponse
from backend.app.db.history_repository import HistoryRepository
from backend.app.db.task_repository import TaskRepository

FILE_ACTION_CANCELLABLE_OPERATIONS = {"copy", "move", "duplicate", "delete"}


class TaskService:
    def __init__(self, repository: TaskRepository, history_repository: HistoryRepository | None = None):
        self._repository = repository
        self._history_repository = history_repository

    def create_task(self, operation: str, source: str, destination: str) -> TaskDetailResponse:
        task = self._repository.create_task(operation=operation, source=source, destination=destination)
        return TaskDetailResponse(**task)

    def get_task(self, task_id: str) -> TaskDetailResponse:
        task = self._repository.get_task(task_id)
        if not task:
            raise AppError(
                code="task_not_found",
                message="Task was not found",
                status_code=404,
                details={"task_id": task_id},
            )
        return TaskDetailResponse(**task)

    def list_tasks(self) -> TaskListResponse:
        tasks = self._repository.list_tasks()
        return TaskListResponse(
            items=[
                TaskListItem(
                    id=task["id"],
                    operation=task["operation"],
                    status=task["status"],
                    source=task["source"],
                    destination=task["destination"],
                    created_at=task["created_at"],
                    finished_at=task["finished_at"],
                )
                for task in tasks
            ]
        )

    def cancel_task(self, task_id: str) -> TaskDetailResponse:
        task = self._repository.get_task(task_id)
        if not task:
            raise AppError(
                code="task_not_found",
                message="Task was not found",
                status_code=404,
                details={"task_id": task_id},
            )
        if task["operation"] not in FILE_ACTION_CANCELLABLE_OPERATIONS:
            raise AppError(
                code="task_not_cancellable",
                message="Task cannot be cancelled",
                status_code=409,
                details={"task_id": task_id, "status": task["status"]},
            )
        if task["status"] not in {"queued", "running", "cancelling"}:
            raise AppError(
                code="task_not_cancellable",
                message="Task cannot be cancelled",
                status_code=409,
                details={"task_id": task_id, "status": task["status"]},
            )

        updated = self._repository.request_cancellation(task_id)
        if not updated:
            raise AppError(
                code="task_not_cancellable",
                message="Task cannot be cancelled",
                status_code=409,
                details={"task_id": task_id, "status": task["status"]},
            )

        if updated["status"] == "cancelled" and self._history_repository:
            self._history_repository.update_entry(entry_id=task_id, status="cancelled")

        return TaskDetailResponse(**updated)
