"""High-level Agent class — upload + submit + poll in one call."""

from __future__ import annotations

from typing import Any, BinaryIO

from curvestone._client import AsyncCurvestone, Curvestone
from curvestone.types.check import CheckResult
from curvestone.types.job import Job


class Agent:
    """High-level synchronous interface for Curvestone.

    Usage::

        from curvestone import Agent

        agent = Agent()  # reads CURVESTONE_API_KEY env var

        result = agent.check(
            case_type="residential_mortgage",
            depth="full_check",
            documents=[open("fact_find.pdf", "rb")],
        )
        print(result.triage)   # "green" | "amber" | "red"
        print(result.findings) # list of Finding objects
    """

    def __init__(
        self,
        *,
        api_key: str | None = None,
        base_url: str | None = None,
        timeout: float = 60.0,
        poll_interval: float = 1.0,
        poll_timeout: float = 300.0,
    ) -> None:
        self._client = Curvestone(api_key=api_key, base_url=base_url, timeout=timeout)
        self._poll_interval = poll_interval
        self._poll_timeout = poll_timeout

    def close(self) -> None:
        self._client.close()

    def __enter__(self) -> Agent:
        return self

    def __exit__(self, *args: Any) -> None:
        self.close()

    def check(
        self,
        *,
        case_type: str,
        depth: str,
        documents: list[BinaryIO] | None = None,
        file_ids: list[str] | None = None,
        variations: list[str] | None = None,
        reference: str | None = None,
        webhook_url: str | None = None,
        poll_interval: float | None = None,
        poll_timeout: float | None = None,
    ) -> CheckResult:
        """Run a full compliance check: upload files, submit, poll, return result.

        Args:
            case_type: e.g. "residential_mortgage", "buy_to_let"
            depth: e.g. "admin_check", "full_check"
            documents: File objects to upload (mutually exclusive with file_ids)
            file_ids: Pre-uploaded file IDs
            variations: e.g. ["debt_consolidation", "interest_only"]
            reference: Your reference string for this check
            webhook_url: URL to receive completion webhook
            poll_interval: Seconds between poll requests (default: 1.0)
            poll_timeout: Max seconds to wait for completion (default: 300)
        """
        ids = list(file_ids or [])

        # Upload any document file objects
        if documents:
            for doc in documents:
                f = self._client.files.upload(doc)
                ids.append(f.file_id)

        # Submit the check
        created = self._client.checks.create(
            case_type=case_type,
            depth=depth,
            file_ids=ids or None,
            variations=variations,
            reference=reference,
            webhook_url=webhook_url,
        )

        # Poll until complete
        job = self._client.jobs.poll(
            created.job_id,
            interval=poll_interval or self._poll_interval,
            timeout=poll_timeout or self._poll_timeout,
        )

        return _job_to_check_result(job)

    def ask(
        self,
        question: str,
        *,
        context: dict | None = None,
        thread_id: str | None = None,
        documents: list[BinaryIO] | None = None,
        poll_timeout: float | None = None,
    ) -> str:
        """Ask a compliance question and get an answer string."""
        created = self._client.ask.create(
            question=question,
            context=context,
            thread_id=thread_id,
        )
        job = self._client.jobs.poll(
            created.job_id,
            interval=self._poll_interval,
            timeout=poll_timeout or self._poll_timeout,
        )
        return (job.result or {}).get("answer", "")


class AsyncAgent:
    """High-level async interface for Curvestone.

    Usage::

        from curvestone import AsyncAgent

        agent = AsyncAgent()

        result = await agent.check(
            case_type="residential_mortgage",
            depth="full_check",
            documents=[open("fact_find.pdf", "rb")],
        )
    """

    def __init__(
        self,
        *,
        api_key: str | None = None,
        base_url: str | None = None,
        timeout: float = 60.0,
        poll_interval: float = 1.0,
        poll_timeout: float = 300.0,
    ) -> None:
        self._client = AsyncCurvestone(api_key=api_key, base_url=base_url, timeout=timeout)
        self._poll_interval = poll_interval
        self._poll_timeout = poll_timeout

    async def close(self) -> None:
        await self._client.close()

    async def __aenter__(self) -> AsyncAgent:
        return self

    async def __aexit__(self, *args: Any) -> None:
        await self.close()

    async def check(
        self,
        *,
        case_type: str,
        depth: str,
        documents: list[BinaryIO] | None = None,
        file_ids: list[str] | None = None,
        variations: list[str] | None = None,
        reference: str | None = None,
        webhook_url: str | None = None,
        poll_interval: float | None = None,
        poll_timeout: float | None = None,
    ) -> CheckResult:
        """Run a full compliance check: upload files, submit, poll, return result."""
        ids = list(file_ids or [])

        if documents:
            for doc in documents:
                f = await self._client.files.upload(doc)
                ids.append(f.file_id)

        created = await self._client.checks.create(
            case_type=case_type,
            depth=depth,
            file_ids=ids or None,
            variations=variations,
            reference=reference,
            webhook_url=webhook_url,
        )

        job = await self._client.jobs.poll(
            created.job_id,
            interval=poll_interval or self._poll_interval,
            timeout=poll_timeout or self._poll_timeout,
        )

        return _job_to_check_result(job)

    async def ask(
        self,
        question: str,
        *,
        context: dict | None = None,
        thread_id: str | None = None,
        documents: list[BinaryIO] | None = None,
        poll_timeout: float | None = None,
    ) -> str:
        """Ask a compliance question and get an answer string."""
        created = await self._client.ask.create(
            question=question,
            context=context,
            thread_id=thread_id,
        )
        job = await self._client.jobs.poll(
            created.job_id,
            interval=self._poll_interval,
            timeout=poll_timeout or self._poll_timeout,
        )
        return (job.result or {}).get("answer", "")


def _job_to_check_result(job: Job) -> CheckResult:
    """Convert a completed Job to a CheckResult."""
    if job.status == "failed":
        from curvestone._exceptions import CurvestoneError

        error = job.error or {}
        raise CurvestoneError(
            error.get("message", "Check failed"),
            code=error.get("code"),
        )

    result = job.result or {}
    return CheckResult.model_validate(result)
