"""Notion notes provider adapter (internal token mode)."""

from __future__ import annotations

from typing import Any

import requests
from requests.exceptions import RequestException
from sqlalchemy.orm import Session

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

REQUEST_TIMEOUT_SECONDS = 20
NOTION_API_BASE = "https://api.notion.com/v1"
NOTION_VERSION = "2022-06-28"


class NotionNotesProvider:
    """Notion adapter with internal integration token."""

    provider_id = "notion"
    display_name = "Notion"

    def __init__(self, *, token: str, page_id: str | None = None, database_id: str | None = None):
        self._token = (token or "").strip()
        self._page_id = (page_id or "").strip() or None
        self._database_id = (database_id or "").strip() or None
        if not self._token:
            raise ProviderNotConfiguredError("Notion internal integration token is required")
        if not self._page_id and not self._database_id:
            raise ProviderNotConfiguredError("Notion page_id or database_id is required")

    def _headers(self) -> dict[str, str]:
        return {
            "Authorization": f"Bearer {self._token}",
            "Notion-Version": NOTION_VERSION,
            "Content-Type": "application/json",
        }

    def _request(self, method: str, path: str, *, json_payload: dict[str, Any] | None = None) -> dict[str, Any] | list[Any]:
        url = f"{NOTION_API_BASE}{path}"
        try:
            response = requests.request(
                method=method,
                url=url,
                headers=self._headers(),
                json=json_payload,
                timeout=REQUEST_TIMEOUT_SECONDS,
            )
        except RequestException as exc:
            raise ProviderConnectionError(f"Notion request failed: {exc}") from exc

        if response.status_code >= 400:
            detail = response.text.strip() or "Notion API request failed"
            raise ProviderConnectionError(f"Notion API error ({response.status_code}): {detail}")

        try:
            return response.json()
        except ValueError as exc:
            raise ProviderConnectionError("Notion API returned invalid JSON") from exc

    @staticmethod
    def _extract_title(item: dict[str, Any]) -> str:
        properties = item.get("properties")
        if isinstance(properties, dict):
            for _, value in properties.items():
                if not isinstance(value, dict):
                    continue
                title = value.get("title")
                if isinstance(title, list) and title:
                    first = title[0]
                    if isinstance(first, dict):
                        plain = first.get("plain_text")
                        if isinstance(plain, str) and plain.strip():
                            return plain.strip()
        return "Notion Page"

    def search(self, *, query: str, limit: int = 5, db: Session | None = None) -> list[NotesHit]:
        payload = self._request(
            "POST",
            "/search",
            json_payload={
                "query": query,
                "page_size": max(1, min(limit, 20)),
                "filter": {"property": "object", "value": "page"},
            },
        )
        results = payload.get("results") if isinstance(payload, dict) else None
        if not isinstance(results, list):
            return []

        hits: list[NotesHit] = []
        for item in results:
            if not isinstance(item, dict):
                continue
            page_id = str(item.get("id", ""))
            title = self._extract_title(item)
            source = str(item.get("url", ""))
            hits.append(
                NotesHit(
                    provider=self.provider_id,
                    id=page_id,
                    title=title,
                    snippet=title,
                    source=source,
                    raw={"object": item.get("object")},
                ),
            )
        return hits

    def create_note(self, *, title: str, content: str, db: Session | None = None) -> str:
        children = [
            {
                "object": "block",
                "type": "paragraph",
                "paragraph": {"rich_text": [{"type": "text", "text": {"content": content[:1900]}}]},
            },
        ]
        if self._database_id:
            payload = self._request(
                "POST",
                "/pages",
                json_payload={
                    "parent": {"database_id": self._database_id},
                    "properties": {"Name": {"title": [{"type": "text", "text": {"content": title[:120]}}]}},
                    "children": children,
                },
            )
        else:
            payload = self._request(
                "POST",
                "/pages",
                json_payload={
                    "parent": {"page_id": self._page_id},
                    "properties": {"title": [{"type": "text", "text": {"content": title[:120]}}]},
                    "children": children,
                },
            )
        if not isinstance(payload, dict):
            raise ProviderConnectionError("Unexpected Notion page response")
        return str(payload.get("id", ""))

    def append_note(self, *, target_id: str, content: str, db: Session | None = None) -> None:
        _ = self._request(
            "PATCH",
            f"/blocks/{target_id}/children",
            json_payload={
                "children": [
                    {
                        "object": "block",
                        "type": "paragraph",
                        "paragraph": {"rich_text": [{"type": "text", "text": {"content": content[:1900]}}]},
                    },
                ],
            },
        )

    def test_connection(self, db: Session | None = None) -> ProviderConnectionResult:
        try:
            payload = self._request("GET", "/users/me")
        except Exception as exc:
            return ProviderConnectionResult(ok=False, detail=str(exc))
        if isinstance(payload, dict) and payload.get("object") == "user":
            return ProviderConnectionResult(ok=True, detail="Notion connection successful")
        return ProviderConnectionResult(ok=False, detail="Notion test returned unexpected payload")
