"""
aiel_sdk.jira.remote
====================

Remote-backed Jira operations via the AIEL Integrations API.

This module provides :class:`~aiel_sdk.jira.remote.RemoteJira`, a production
Jira tool wrapper. Each method maps 1:1 to a backend action executed against a
selected ``connection_id``:

- jira.myself
- jira.list_sites
- jira.create_issue
- jira.add_comment
- jira.transition_issue

Key identifiers
---------------
connection_id:
    Explicit connection identifier returned by your Integrations list endpoint.
    Recommended for deterministic multi-agent behavior.

workspace_id / project_id:
    RemoteJira is bound to a workspace + project at construction time.

Errors
------
- Local validation raises ValueError.
- Remote failures surface as SDK client exceptions.

See also
--------
- :class:`~aiel_sdk.jira.types.JiraCreateIssueRequest`
- :class:`~aiel_sdk.jira.types.JiraAddCommentRequest`
- :class:`~aiel_sdk.jira.types.JiraTransitionIssueRequest`
"""
from __future__ import annotations

from typing import Any, Dict, List, Optional

from ...client import AielClient
from .types import (
    JiraMyself,
    JiraAccessibleSite,
    JiraCreateIssueRequest,
    JiraAddCommentRequest,
    JiraTransitionIssueRequest,
    DEFAULT_JIRA_CAPABILITIES,
    JiraCapabilities,
)

Json = Dict[str, Any]


def _ensure_non_empty(value: str, name: str) -> str:
    v = (value or "").strip()
    if not v:
        raise ValueError(f"{name} must be non-empty")
    return v

class RemoteJira:
    """
    RemoteJira
    ==========
    Production Jira tool wrapper backed by IntegrationsService.invoke_action.
    """

    @property
    def capabilities(self) -> JiraCapabilities:
        return DEFAULT_JIRA_CAPABILITIES

    def __init__(
        self,
        client: AielClient,
        *,
        workspace_id: str,
        project_id: str,
        connection_id: str,
    ) -> None:
        self._c = client
        self._ws = _ensure_non_empty(workspace_id, "workspace_id")
        self._proj = _ensure_non_empty(project_id, "project_id")
        self._conn = _ensure_non_empty(connection_id, "connection_id")

    def _invoke(
        self,
        *,
        action: str,
        params: Optional[Json] = None,
        request_id: str | None = None,
    ) -> Any:
        """
        Invoke a Jira action using IntegrationsService.invoke_action.

        Matches your service signature:

            invoke_action(ws, proj, connection_id, action, payload={"params": {...}}, request_id=?)
        """
        return self._c.integrations.invoke_action(
            self._ws,
            self._proj,
            connection_id=self._conn,
            action=action,
            payload={"params": params or {}},
            request_id=request_id,
        )

    # ---- Identity / discovery ----

    def myself(self, *, request_id: str | None = None) -> JiraMyself:
        raw = self._invoke(action="jira.myself", params={}, request_id=request_id)
        if isinstance(raw, dict):
            return JiraMyself.from_json(raw)
        return JiraMyself.from_json({"raw": raw})

    def list_sites(self, *, request_id: str | None = None) -> List[JiraAccessibleSite]:
        raw = self._invoke(action="jira.list_sites", params={}, request_id=request_id)
        return raw

    # ---- Issues ----

    def create_issue(self, req: JiraCreateIssueRequest, *, request_id: str | None = None) -> Json:
        raw = self._invoke(action="jira.create_issue", params=req.to_params(), request_id=request_id)
        return dict(raw or {}) if isinstance(raw, dict) else {"raw": raw}

    def add_comment(self, req: JiraAddCommentRequest, *, request_id: str | None = None) -> Json:
        raw = self._invoke(action="jira.add_comment", params=req.to_params(), request_id=request_id)
        return dict(raw or {}) if isinstance(raw, dict) else {"raw": raw}

    def transition_issue(self, req: JiraTransitionIssueRequest, *, request_id: str | None = None) -> Json:
        raw = self._invoke(action="jira.transition_issue", params=req.to_params(), request_id=request_id)
        return dict(raw or {}) if isinstance(raw, dict) else {"raw": raw}