"""Todoist integration adapter for unified task provider interface."""

from __future__ import annotations

from typing import Any

from app.services import todoist_service
from app.services.integrations.errors import ProviderConnectionError, ProviderNotConfiguredError
from app.services.integrations.types import ProviderConnectionResult, UnifiedTask


class TodoistTaskProvider:
    """Task provider backed by Todoist REST API."""

    provider_id = "todoist"
    display_name = "Todoist"

    @staticmethod
    def _to_unified(item: dict[str, Any]) -> UnifiedTask:
        due = item.get("due") if isinstance(item.get("due"), dict) else {}
        due_date = str(due.get("date")).strip() if due.get("date") else None
        due_string = str(due.get("string")).strip() if due.get("string") else None
        is_completed = str(item.get("status", "")).strip().lower() == "completed"
        return UnifiedTask(
            provider="todoist",
            id=str(item.get("id", "")),
            title=str(item.get("content", "")).strip() or "Untitled task",
            description=str(item.get("description", "")).strip() or None,
            due_date=due_date,
            due_string=due_string,
            priority=int(item.get("priority")) if item.get("priority") is not None else None,
            completed=is_completed,
            raw={k: v for k, v in item.items() if k not in {"id", "content", "description", "due", "priority"}},
        )

    def list_tasks(self, *, include_completed: bool = False) -> list[UnifiedTask]:
        try:
            items = todoist_service.list_tasks()
        except todoist_service.TodoistConfigError as exc:
            raise ProviderNotConfiguredError(str(exc)) from exc
        except todoist_service.TodoistAPIError as exc:
            raise ProviderConnectionError(f"Todoist API error ({exc.status_code}): {exc.detail}") from exc
        tasks = [self._to_unified(item) for item in items]
        if include_completed:
            return tasks
        return [item for item in tasks if not item.completed]

    def create_task(self, *, content: str, description: str | None = None, due_string: str | None = None) -> UnifiedTask:
        try:
            item = todoist_service.create_task(content=content, description=description, due_string=due_string)
        except todoist_service.TodoistConfigError as exc:
            raise ProviderNotConfiguredError(str(exc)) from exc
        except todoist_service.TodoistAPIError as exc:
            raise ProviderConnectionError(f"Todoist API error ({exc.status_code}): {exc.detail}") from exc
        return self._to_unified(item)

    def complete_task(self, *, task_id: str) -> None:
        try:
            todoist_service.complete_task(task_id=task_id)
        except todoist_service.TodoistConfigError as exc:
            raise ProviderNotConfiguredError(str(exc)) from exc
        except todoist_service.TodoistAPIError as exc:
            raise ProviderConnectionError(f"Todoist API error ({exc.status_code}): {exc.detail}") from exc

    def update_due(self, *, task_id: str, due_string: str) -> UnifiedTask | None:
        # Todoist v1 does not expose due update in existing service path.
        return None

    def test_connection(self) -> ProviderConnectionResult:
        try:
            _ = todoist_service.list_tasks()
        except todoist_service.TodoistConfigError as exc:
            return ProviderConnectionResult(ok=False, detail=str(exc))
        except todoist_service.TodoistAPIError as exc:
            return ProviderConnectionResult(ok=False, detail=f"Todoist API error ({exc.status_code}): {exc.detail}")
        except Exception as exc:  # pragma: no cover - defensive runtime branch
            return ProviderConnectionResult(ok=False, detail=f"Todoist connection failed: {exc}")
        return ProviderConnectionResult(ok=True, detail="Todoist connection successful")
