"""Nexus365Desk Public API — Python sample.

Install:   pip install msal requests
Configure: export NEXUS365_TENANT_ID / CLIENT_ID / CLIENT_SECRET / SITE_ID
           (values come from the Nexus365Desk SPFx setup wizard)

Uses msal for token caching so you don't refetch on every call.
"""

from __future__ import annotations

import os
import sys
import requests
import msal

TENANT_ID = os.environ.get("NEXUS365_TENANT_ID", "your-tenant-id-guid")
CLIENT_ID = os.environ.get("NEXUS365_CLIENT_ID", "your-client-id-guid")
CLIENT_SECRET = os.environ.get("NEXUS365_CLIENT_SECRET", "your-client-secret")
SITE_ID = os.environ.get("NEXUS365_SITE_ID", "contoso.sharepoint.com,site-collection-guid,site-guid")

GRAPH_BASE = f"https://graph.microsoft.com/v1.0/sites/{SITE_ID}"
SCOPE = ["https://graph.microsoft.com/.default"]


class Nexus365Client:
    def __init__(self) -> None:
        self._app = msal.ConfidentialClientApplication(
            client_id=CLIENT_ID,
            client_credential=CLIENT_SECRET,
            authority=f"https://login.microsoftonline.com/{TENANT_ID}",
        )

    def _token(self) -> str:
        result = self._app.acquire_token_for_client(scopes=SCOPE)
        if "access_token" not in result:
            raise RuntimeError(f"Token acquisition failed: {result.get('error_description')}")
        return result["access_token"]

    def _headers(self) -> dict:
        return {"Authorization": f"Bearer {self._token()}"}

    # ── Tickets ──────────────────────────────────────────────────

    def list_open_tickets(self, top: int = 50) -> list[dict]:
        resp = requests.get(
            f"{GRAPH_BASE}/lists/SD_Tickets/items",
            params={
                "$expand": "fields",
                "$filter": "fields/SD_Status eq 'New' or fields/SD_Status eq 'Assigned' or fields/SD_Status eq 'In Progress'",
                "$orderby": "fields/Created desc",
                "$top": top,
            },
            headers=self._headers(),
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json().get("value", [])

    def get_ticket(self, item_id: str) -> dict:
        resp = requests.get(
            f"{GRAPH_BASE}/lists/SD_Tickets/items/{item_id}",
            params={"$expand": "fields"},
            headers=self._headers(),
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()

    def create_ticket(
        self,
        title: str,
        description: str,
        submitted_by: str,
        submitted_by_name: str,
        priority: str = "Medium",
        category: str = "Other",
    ) -> dict:
        resp = requests.post(
            f"{GRAPH_BASE}/lists/SD_Tickets/items",
            json={
                "fields": {
                    "Title": title,
                    "SD_Description": description,
                    "SD_Priority": priority,
                    "SD_Status": "New",
                    "SD_Category": category,
                    "SD_SubmittedBy": submitted_by,
                    "SD_SubmittedByName": submitted_by_name,
                    "SD_SubmittedByEmail": submitted_by,
                }
            },
            headers={**self._headers(), "Content-Type": "application/json"},
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()

    def set_ticket_status(self, item_id: str, status: str, assigned_to: str | None = None) -> dict:
        fields: dict = {"SD_Status": status}
        if assigned_to:
            fields["SD_AssignedTo"] = assigned_to
        resp = requests.patch(
            f"{GRAPH_BASE}/lists/SD_Tickets/items/{item_id}/fields",
            json=fields,
            headers={**self._headers(), "Content-Type": "application/json", "If-Match": "*"},
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()

    # ── Comments ─────────────────────────────────────────────────

    def add_comment(
        self,
        ticket_id: int,
        body: str,
        author_email: str,
        author_name: str,
        internal: bool = False,
    ) -> dict:
        resp = requests.post(
            f"{GRAPH_BASE}/lists/SD_Comments/items",
            json={
                "fields": {
                    "Title": body[:80],
                    "SD_TicketId": ticket_id,
                    "SD_Body": body,
                    "SD_AuthorEmail": author_email,
                    "SD_AuthorName": author_name,
                    "SD_IsInternal": internal,
                }
            },
            headers={**self._headers(), "Content-Type": "application/json"},
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()


if __name__ == "__main__":
    client = Nexus365Client()

    # Example: list the 10 most recent open tickets.
    for t in client.list_open_tickets(top=10):
        f = t.get("fields", {})
        print(f"#{t['id']:>5} [{f.get('SD_Priority','?'):>6}] {f.get('Title','(no title)')}")

    if len(sys.argv) > 1 and sys.argv[1] == "create":
        created = client.create_ticket(
            title="Printer offline on floor 3",
            description="HP M553 not responding since 09:00.",
            submitted_by="user@contoso.com",
            submitted_by_name="Facilities",
            priority="Medium",
            category="Hardware",
        )
        print(f"Created ticket id={created['id']}")
