"""Vastian Pocket Transcript — API Client.

Thin wrapper around the Pocket Public API for retrieving meeting
recordings, transcripts, summaries, action items, and mind maps.

Requires the ``requests`` library and a ``POCKET_API_KEY`` env var
(or pass *api_key* directly).
"""

from __future__ import annotations

import logging
import os
from typing import Any

import requests

logger = logging.getLogger(__name__)

DEFAULT_BASE_URL = "https://public.heypocketai.com"


class PocketClient:
    """Thin wrapper for the Pocket Public API.

    Uses the API key in the ``Authorization`` header as a Bearer token.
    """

    def __init__(
        self,
        api_key: str | None = None,
        base_url: str = DEFAULT_BASE_URL,
    ) -> None:
        self.base_url = base_url.rstrip("/")
        self.api_key = api_key or os.getenv("POCKET_API_KEY")
        if not self.api_key:
            raise ValueError(
                "Pocket API key not provided. Set POCKET_API_KEY env var or pass api_key."
            )
        self.session = requests.Session()
        self.session.headers.update({"Authorization": f"Bearer {self.api_key}"})

    # ------------------------------------------------------------------
    # Core endpoints
    # ------------------------------------------------------------------

    def _url(self, path: str) -> str:
        return f"{self.base_url}{path}"

    def list_recordings(
        self,
        start_date: str | None = None,
        end_date: str | None = None,
        tag_ids: str | None = None,
        page: int = 1,
        limit: int = 20,
    ) -> dict[str, Any]:
        """List recordings with optional date / tag filters."""
        params: dict[str, Any] = {"page": page, "limit": limit}
        if start_date:
            params["start_date"] = start_date
        if end_date:
            params["end_date"] = end_date
        if tag_ids:
            params["tag_ids"] = tag_ids
        resp = self.session.get(
            self._url("/api/v1/public/recordings"),
            params=params,
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()

    def get_recording(
        self,
        recording_id: str,
        include_transcript: bool = True,
        include_summarizations: bool = True,
    ) -> dict[str, Any]:
        """Retrieve a single recording with optional transcript / summaries."""
        params = {
            "include_transcript": include_transcript,
            "include_summarizations": include_summarizations,
        }
        resp = self.session.get(
            self._url(f"/api/v1/public/recordings/{recording_id}"),
            params=params,
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()

    def get_audio_url(
        self,
        recording_id: str,
        expires_in: int = 3600,
    ) -> dict[str, Any]:
        """Get a pre-signed audio URL for a recording."""
        params = {"expires_in": expires_in}
        resp = self.session.get(
            self._url(f"/api/v1/public/recordings/{recording_id}/audio-url"),
            params=params,
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()


# ======================================================================
# Extraction helpers (work on a ``get_recording`` response payload)
# ======================================================================


def _get_dict(d: Any) -> dict[str, Any]:
    """Safely coerce *d* to a dict."""
    return d if isinstance(d, dict) else {}


def extract_latest_summary(
    data: dict[str, Any],
) -> tuple[str | None, dict[str, Any] | None]:
    """Extract the latest summary text from a recording detail response.

    The API returns summarizations as a dict with keys like
    ``v2_summary``, ``v2_action_items``, etc.  Each version is a dict
    with ``markdown`` and ``version`` keys.

    Preference order: v2_summary > v2_mind_map > v1_summary > summary.

    Returns:
        ``(summary_text, raw_summary_obj)`` or ``(None, None)``.
    """
    payload = _get_dict(data).get("data")
    rec = _get_dict(payload)

    summ_dict = _get_dict(rec.get("summarizations", {}))
    logger.debug("summarizations keys: %s", list(summ_dict.keys()))

    # Build candidate list in preference order
    candidates: list[tuple[str, Any]] = []
    for key in ("v2_summary", "v2_mind_map", "v1_summary", "summary"):
        if key in summ_dict:
            candidates.append((key, summ_dict[key]))

    # Fallback: take whatever is available
    if not candidates and summ_dict:
        candidates = list(summ_dict.items())

    for key, summ_obj in candidates:
        logger.debug("Checking %s, type=%s", key, type(summ_obj))

        if isinstance(summ_obj, dict):
            if "markdown" in summ_obj:
                text = summ_obj.get("markdown")
                if isinstance(text, str) and text.strip():
                    logger.debug("Found markdown in %s, length=%d", key, len(text))
                    return text.strip(), summ_obj

            for field in ("text", "content", "summary"):
                text = summ_obj.get(field)
                if isinstance(text, str) and text.strip():
                    logger.debug("Found %s in %s, length=%d", field, key, len(text))
                    return text.strip(), summ_obj

        elif isinstance(summ_obj, str) and summ_obj.strip():
            logger.debug("%s is string, length=%d", key, len(summ_obj))
            return summ_obj.strip(), None

    logger.debug("No summary text found in any candidate")
    return None, None


def extract_transcript_text(data: dict[str, Any]) -> str | None:
    """Extract transcript text with speaker labels.

    If segments are available, formats as ``SPEAKER_XX: text``.
    Otherwise returns the plain text field.
    """
    payload = _get_dict(data).get("data")
    rec = _get_dict(payload)
    transcript = rec.get("transcript")

    if isinstance(transcript, dict):
        segments = transcript.get("segments")
        if isinstance(segments, list) and segments:
            lines: list[str] = []
            for seg in segments:
                if isinstance(seg, dict):
                    text = seg.get("text") or seg.get("originalText") or ""
                    speaker = seg.get("speaker") or "UNKNOWN"
                    if text:
                        lines.append(f"{speaker}: {text}")
            if lines:
                return "\n".join(lines)

        for field in ("text", "content", "transcript_text"):
            val = transcript.get(field)
            if isinstance(val, str) and val.strip():
                return val.strip()
    elif isinstance(transcript, str) and transcript.strip():
        return transcript.strip()

    for key in ("transcript_raw", "raw_transcript"):
        val = rec.get(key)
        if isinstance(val, str) and val.strip():
            return val.strip()

    return None


def extract_mind_map(data: dict[str, Any]) -> str | None:
    """Extract mind map from summarizations and return formatted text."""
    payload = _get_dict(data).get("data")
    rec = _get_dict(payload)
    summ_dict = _get_dict(rec.get("summarizations", {}))

    mind_map = _get_dict(summ_dict.get("v2_mind_map"))
    nodes = mind_map.get("nodes")

    if not isinstance(nodes, list) or not nodes:
        return None

    lines: list[str] = []
    for node in nodes:
        if isinstance(node, dict):
            title = node.get("title", "").strip()
            if not title:
                continue
            node_id = node.get("node_id", "")
            parent_id = node.get("parent_node_id", "")
            indent = "  " if node_id != parent_id else ""
            lines.append(f"{indent}\u2022 {title}")

    return "\n".join(lines) if lines else None


def extract_action_items(data: dict[str, Any]) -> list[dict[str, Any]] | None:
    """Extract action items from summarizations.

    Looks for ``v2_action_items.actionItems``.
    Each item has: description, assignee, priority, dueDate, etc.
    """
    payload = _get_dict(data).get("data")
    rec = _get_dict(payload)
    summ_dict = _get_dict(rec.get("summarizations", {}))

    action_items_obj = _get_dict(summ_dict.get("v2_action_items"))
    items = action_items_obj.get("actionItems")

    if isinstance(items, list) and items:
        return items

    return None


def get_all_summary_versions(data: dict[str, Any]) -> list[dict[str, Any]]:
    """Return all available summary versions from summarizations.

    Each entry: ``{key, text, version, label}``.
    """
    payload = _get_dict(data).get("data")
    rec = _get_dict(payload)
    summ_dict = _get_dict(rec.get("summarizations", {}))

    versions: list[dict[str, Any]] = []
    for key in ("v2_summary", "v1_summary", "summary"):
        if key in summ_dict:
            summ_obj = _get_dict(summ_dict[key])
            text = summ_obj.get("markdown") or summ_obj.get("text") or summ_obj.get("content")
            if isinstance(text, str) and text.strip():
                version = summ_obj.get("version", key)
                versions.append(
                    {
                        "key": key,
                        "text": text.strip(),
                        "version": version,
                        "label": f"{key.replace('_', ' ').title()} (v{version})",
                    }
                )

    return versions


def get_all_mind_map_versions(data: dict[str, Any]) -> list[dict[str, Any]]:
    """Return all available mind map versions from summarizations.

    Each entry: ``{key, text, type, label}``.
    """
    payload = _get_dict(data).get("data")
    rec = _get_dict(payload)
    summ_dict = _get_dict(rec.get("summarizations", {}))

    versions: list[dict[str, Any]] = []
    for key in ("v2_mind_map", "v1_mind_map", "mind_map"):
        if key in summ_dict:
            mm_obj = _get_dict(summ_dict[key])

            text: str | None = None
            if "nodes" in mm_obj and isinstance(mm_obj["nodes"], list):
                lines: list[str] = []
                for node in mm_obj["nodes"]:
                    if isinstance(node, dict):
                        title = node.get("title", "").strip()
                        if not title:
                            continue
                        node_id = node.get("node_id", "")
                        parent_id = node.get("parent_node_id", "")
                        indent = "  " if node_id != parent_id else ""
                        lines.append(f"{indent}\u2022 {title}")
                if lines:
                    text = "\n".join(lines)
            elif "markdown" in mm_obj:
                text = _get_dict(mm_obj).get("markdown")

            if text and isinstance(text, str) and text.strip():
                mm_type = mm_obj.get("type", key)
                versions.append(
                    {
                        "key": key,
                        "text": text.strip(),
                        "type": mm_type,
                        "label": f"{key.replace('_', ' ').title()}",
                    }
                )

    return versions
