"""
Hearing Service — Virtual Hearing Room via Zoom Meetings API (OAuth 2.0 Server-to-Server)
Handles meeting creation, join link generation, and hearing management.

Setup:
  1. Go to https://marketplace.zoom.us → Build App → Server-to-Server OAuth
  2. Add scopes: meeting:write:admin, meeting:read:admin
  3. Copy Account ID, Client ID, Client Secret to your .env file
"""
import os
import time
import requests
from typing import Optional
from sqlalchemy.orm import Session

from ..models.fyp2_models import Hearing
from ..models.models import Case
from ..config import ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRET

ZOOM_TOKEN_URL  = "https://zoom.us/oauth/token"
ZOOM_API_BASE   = "https://api.zoom.us/v2"


def _jitsi_fallback(case_ref: str) -> dict:
    """Build a Jitsi Meet room with a random token so outsiders can't guess the URL."""
    import secrets
    room_name = f"LegalEase-Hearing-{case_ref.replace(' ', '-')}-{secrets.token_hex(4)}"
    url = f"https://meet.jit.si/{room_name}"
    return {
        "meeting_id": room_name,
        "join_url":   url,
        "start_url":  url,
        "password":   "",
        "provider":   "jitsi",
    }

# Module-level token cache — refreshed automatically when expired
_zoom_token: dict = {"access_token": "", "expires_at": 0}


# ── Zoom OAuth helpers ───────────────────────────────────────────────────────

def _get_zoom_token() -> str:
    """
    Get a valid Zoom Server-to-Server OAuth access token.
    Caches the token and refreshes it only when expired.
    Returns empty string if credentials are not configured.
    """
    global _zoom_token

    if not all([ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRET]):
        return ""

    # Return cached token if still valid (with 60s buffer)
    if _zoom_token["access_token"] and time.time() < _zoom_token["expires_at"] - 60:
        return _zoom_token["access_token"]

    try:
        resp = requests.post(
            ZOOM_TOKEN_URL,
            params={"grant_type": "account_credentials", "account_id": ZOOM_ACCOUNT_ID},
            auth=(ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRET),
            timeout=10,
        )
        data = resp.json()
        _zoom_token["access_token"] = data.get("access_token", "")
        _zoom_token["expires_at"]   = time.time() + data.get("expires_in", 3600)
        return _zoom_token["access_token"]
    except Exception as e:
        print(f"[Hearing] Zoom token fetch failed: {e}")
        return ""


def _zoom_headers() -> dict:
    return {
        "Authorization": f"Bearer {_get_zoom_token()}",
        "Content-Type":  "application/json",
    }


# ── Zoom Meeting creation ────────────────────────────────────────────────────

def create_zoom_meeting(case_ref: str, scheduled_date: str, scheduled_time: str, duration_mins: int = 60) -> dict:
    """
    Create a Zoom meeting for a virtual hearing.
    Returns dict with 'join_url', 'start_url', 'meeting_id', 'password', 'provider'.
    Falls back to Jitsi Meet if Zoom credentials are not configured.
    """
    token = _get_zoom_token()
    if not token:
        # Fallback: Jitsi Meet — no API key, no account, works in browser
        return _jitsi_fallback(case_ref)

    # Combine date + time for Zoom's start_time field (ISO 8601)
    # e.g. "2026-09-15" + "10:00" → "2026-09-15T10:00:00"
    start_time = f"{scheduled_date}T{scheduled_time.replace(' ', '')}:00" if scheduled_time else f"{scheduled_date}T10:00:00"

    payload = {
        "topic":       f"LegalEase AI Hearing — {case_ref}",
        "type":        2,                     # 2 = Scheduled meeting
        "start_time":  start_time,
        "duration":    duration_mins,
        "timezone":    "Asia/Karachi",
        "password":    _make_password(case_ref),
        "settings": {
            "host_video":            True,
            "participant_video":     True,
            "join_before_host":      False,   # Participants wait in lobby
            "mute_upon_entry":       True,
            "waiting_room":          True,    # Judge admits each party
            "auto_recording":        "cloud", # Auto-record to Zoom cloud
            "alternative_hosts":     "",
        },
        "agenda": f"Virtual Court Hearing for Case {case_ref} — LegalEase AI Platform",
    }

    try:
        resp = requests.post(
            f"{ZOOM_API_BASE}/users/me/meetings",
            headers=_zoom_headers(),
            json=payload,
            timeout=15,
        )
        data = resp.json()

        if resp.status_code not in (200, 201):
            raise Exception(f"Zoom API error {resp.status_code}: {data}")

        return {
            "meeting_id":  str(data.get("id", "")),
            "join_url":    data.get("join_url", ""),
            "start_url":   data.get("start_url", ""),   # Only for host
            "password":    data.get("password", ""),
            "provider":    "zoom",
        }
    except Exception as e:
        print(f"[Hearing] Zoom meeting creation failed: {e}. Falling back to Jitsi.")
        return _jitsi_fallback(case_ref)


def delete_zoom_meeting(meeting_id: str) -> bool:
    """Delete a Zoom meeting after the hearing is complete."""
    token = _get_zoom_token()
    if not token or not meeting_id.isdigit():
        return True  # Jitsi rooms need no deletion
    try:
        requests.delete(
            f"{ZOOM_API_BASE}/meetings/{meeting_id}",
            headers=_zoom_headers(),
            timeout=10,
        )
        return True
    except Exception as e:
        print(f"[Hearing] Zoom meeting deletion failed: {e}")
        return False


def _make_password(case_ref: str) -> str:
    """Generate a short numeric Zoom password from the case reference."""
    import hashlib
    h = hashlib.md5(case_ref.encode()).hexdigest()
    return h[:6].upper()   # e.g. "A3F9B1" — Zoom allows alphanumeric passwords


# ── Database helpers ─────────────────────────────────────────────────────────

def schedule_hearing(
    db: Session,
    case_id: int,
    filing_id: int,
    scheduled_date: str,
    scheduled_time: str,
    hearing_type: str,
    judge_name: str,
) -> "Hearing":
    """
    Schedule a new hearing: creates Zoom meeting and saves everything to DB.
    """
    case = db.query(Case).filter(Case.id == case_id).first()
    case_ref = getattr(case, "case_reference_no", f"CASE-{case_id}") if case else f"CASE-{case_id}"

    # Create Zoom meeting (or Jitsi fallback)
    meeting = create_zoom_meeting(case_ref, scheduled_date, scheduled_time)

    hearing = Hearing(
        case_id         = case_id,
        filing_id       = filing_id,
        scheduled_date  = scheduled_date,
        scheduled_time  = scheduled_time,
        hearing_type    = hearing_type,
        judge_name      = judge_name,
        zoom_meeting_id = meeting.get("meeting_id", ""),
        zoom_join_url   = meeting.get("join_url", ""),
        zoom_start_url  = meeting.get("start_url", ""),   # host-only URL
        zoom_password   = meeting.get("password", ""),
        room_provider   = meeting.get("provider", "jitsi"),
        status          = "scheduled",
    )
    db.add(hearing)
    db.commit()
    db.refresh(hearing)
    return hearing


def get_join_url(hearing: "Hearing", is_host: bool = False) -> str:
    """
    Return the correct URL for a participant.
    Hosts (judge/admin) get the start_url which auto-starts the meeting.
    Participants get the regular join_url.
    """
    if is_host and hearing.zoom_start_url:
        return hearing.zoom_start_url
    return hearing.zoom_join_url or ""


def complete_hearing(db: Session, hearing_id: int, outcome_notes: str) -> Optional["Hearing"]:
    """Mark a hearing as completed and record outcome notes."""
    hearing = db.query(Hearing).filter(Hearing.id == hearing_id).first()
    if not hearing:
        return None
    hearing.status        = "completed"
    hearing.outcome_notes = outcome_notes
    db.commit()
    db.refresh(hearing)
    return hearing


def adjourn_hearing(db: Session, hearing_id: int, next_date: str, next_time: str) -> Optional["Hearing"]:
    """Mark current hearing as adjourned and schedule the next one."""
    hearing = db.query(Hearing).filter(Hearing.id == hearing_id).first()
    if not hearing:
        return None

    next_hearing = schedule_hearing(
        db             = db,
        case_id        = hearing.case_id,
        filing_id      = hearing.filing_id,
        scheduled_date = next_date,
        scheduled_time = next_time,
        hearing_type   = hearing.hearing_type,
        judge_name     = hearing.judge_name,
    )
    hearing.status          = "adjourned"
    hearing.next_hearing_id = next_hearing.id
    db.commit()
    db.refresh(hearing)
    return hearing
