"""
Cloud client — Supabase connection manager.

Config stored in ~/.kodara/config.json:
{
  "supabase_url": "https://xxx.supabase.co",
  "supabase_anon_key": "sb_publishable_..."
}

Session stored in ~/.kodara/auth.json:
{
  "access_token": "...",
  "refresh_token": "...",
  "email": "user@example.com",
  "expires_at": 1234567890
}
"""

from __future__ import annotations

import json
import os
import tempfile
import time
from pathlib import Path
from typing import Any

# Default credentials — written to config.json on first run, never hardcoded in logic.
_DEFAULT_SUPABASE_URL = "https://ehenobyqkkrnisfszyke.supabase.co"
_DEFAULT_SUPABASE_ANON_KEY = "sb_publishable_ymzG5sgLGy_x-WHy910zaw_1xxBNOqZ"


def get_config_path() -> Path:
    """Return path to ~/.kodara/config.json."""
    return Path.home() / ".kodara" / "config.json"


def get_auth_path() -> Path:
    """Return path to ~/.kodara/auth.json."""
    return Path.home() / ".kodara" / "auth.json"


def _atomic_write(path: Path, data: dict) -> None:
    """Write JSON atomically via temp file → rename."""
    path.parent.mkdir(parents=True, exist_ok=True)
    fd, tmp = tempfile.mkstemp(dir=path.parent, prefix=path.name + ".tmp")
    try:
        with os.fdopen(fd, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=2)
        # On Windows, destination must not exist before rename
        if path.exists():
            path.unlink()
        os.rename(tmp, path)
    except Exception:
        try:
            os.unlink(tmp)
        except OSError:
            pass
        raise


def _load_config() -> dict:
    """
    Load ~/.kodara/config.json.
    If missing, create it with defaults and return those defaults.
    """
    cfg_path = get_config_path()
    if cfg_path.exists():
        try:
            return json.loads(cfg_path.read_text(encoding="utf-8"))
        except (json.JSONDecodeError, OSError):
            pass
    # First run — create with defaults
    defaults = {
        "supabase_url": _DEFAULT_SUPABASE_URL,
        "supabase_anon_key": _DEFAULT_SUPABASE_ANON_KEY,
    }
    _atomic_write(cfg_path, defaults)
    return defaults


def get_client() -> Any:
    """
    Return an authenticated Supabase client.

    Reads URL/key from ~/.kodara/config.json (creates with defaults if missing).
    Restores session from ~/.kodara/auth.json if it exists.

    Raises:
        ImportError: if the ``supabase`` package is not installed.
    """
    try:
        from supabase import create_client
    except ImportError as exc:
        raise ImportError(
            "The 'supabase' package is required for cloud features. "
            "Install it with: pip install supabase"
        ) from exc

    cfg = _load_config()
    url = cfg.get("supabase_url", _DEFAULT_SUPABASE_URL)
    key = cfg.get("supabase_anon_key", _DEFAULT_SUPABASE_ANON_KEY)

    client = create_client(url, key)

    # Restore existing session if available
    session = load_session()
    if session:
        try:
            client.auth.set_session(
                session["access_token"],
                session["refresh_token"],
            )
        except Exception:
            # Stale / invalid session — silently ignore; caller can re-auth
            pass

    return client


def save_session(session: Any) -> None:
    """
    Persist auth session data to ~/.kodara/auth.json.

    Accepts either a raw Supabase session object or a plain dict.
    """
    auth_path = get_auth_path()

    if isinstance(session, dict):
        data = session
    else:
        # Supabase session object — extract relevant fields
        user = getattr(session, "user", None)
        email = ""
        if user:
            email = getattr(user, "email", "") or ""

        # expires_at may be on session directly or on user
        expires_at = getattr(session, "expires_at", None)
        if expires_at is None:
            expires_at = int(time.time()) + 3600  # fallback: 1 hour

        data = {
            "access_token": getattr(session, "access_token", ""),
            "refresh_token": getattr(session, "refresh_token", ""),
            "email": email,
            "expires_at": expires_at,
        }

    _atomic_write(auth_path, data)


def load_session() -> dict | None:
    """
    Load session from ~/.kodara/auth.json.

    Returns None if the file does not exist or is unreadable.
    """
    auth_path = get_auth_path()
    if not auth_path.exists():
        return None
    try:
        return json.loads(auth_path.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, OSError):
        return None


def clear_session() -> None:
    """Delete ~/.kodara/auth.json."""
    auth_path = get_auth_path()
    try:
        auth_path.unlink(missing_ok=True)
    except OSError:
        pass


def is_authenticated() -> bool:
    """
    Return True if a valid (non-expired) session exists in auth.json.

    A session is considered expired when ``expires_at`` is in the past.
    """
    session = load_session()
    if not session:
        return False
    expires_at = session.get("expires_at")
    if expires_at is None:
        return False
    return int(expires_at) > int(time.time())
