"""Credential storage for Sibilance TUI.

Stores JWT token and observer info in ~/.sibilance/credentials.json
with 0600 file permissions (owner read/write only).
"""

from __future__ import annotations

import base64
import json
import os
import stat
import time
from dataclasses import dataclass
from pathlib import Path


SIBILANCE_DIR = Path.home() / ".sibilance"
CREDENTIALS_FILE = SIBILANCE_DIR / "credentials.json"
CONFIG_FILE = SIBILANCE_DIR / "config.json"

DEFAULT_SERVER_URL = "https://sibilance.fly.dev"


@dataclass(slots=True)
class Credentials:
    token: str
    observer_id: str
    display_name: str
    expires_at: str = ""


def _ensure_dir() -> None:
    """Create ~/.sibilance/ with restrictive permissions if it doesn't exist."""
    if not SIBILANCE_DIR.exists():
        SIBILANCE_DIR.mkdir(parents=True, mode=0o700)


def read_credentials() -> Credentials | None:
    """Read stored credentials. Returns None if missing or malformed."""
    try:
        if not CREDENTIALS_FILE.exists():
            return None
        raw = CREDENTIALS_FILE.read_text(encoding="utf-8")
        data = json.loads(raw)

        token = data.get("token", "")
        observer_id = data.get("observerId", "")
        display_name = data.get("displayName", "")

        if not token or not observer_id or not display_name:
            return None

        return Credentials(
            token=token,
            observer_id=observer_id,
            display_name=display_name,
            expires_at=data.get("expiresAt", ""),
        )
    except (json.JSONDecodeError, OSError):
        return None


def write_credentials(creds: Credentials) -> None:
    """Write credentials to disk with restrictive file permissions."""
    _ensure_dir()
    payload = {
        "token": creds.token,
        "observerId": creds.observer_id,
        "displayName": creds.display_name,
        "expiresAt": creds.expires_at,
    }
    CREDENTIALS_FILE.write_text(
        json.dumps(payload, indent=2), encoding="utf-8"
    )
    os.chmod(CREDENTIALS_FILE, stat.S_IRUSR | stat.S_IWUSR)


def delete_credentials() -> bool:
    """Delete stored credentials. Returns True if deleted."""
    try:
        if CREDENTIALS_FILE.exists():
            CREDENTIALS_FILE.unlink()
            return True
        return False
    except OSError:
        return False


def has_valid_credentials() -> bool:
    """Check if credentials exist and the JWT hasn't expired."""
    creds = read_credentials()
    if creds is None:
        return False

    try:
        parts = creds.token.split(".")
        if len(parts) != 3:
            return False

        # Decode JWT payload (add padding if needed)
        payload_b64 = parts[1]
        padding = 4 - len(payload_b64) % 4
        if padding != 4:
            payload_b64 += "=" * padding

        payload = json.loads(base64.urlsafe_b64decode(payload_b64))
        exp = payload.get("exp", 0)
        return exp > time.time()
    except (json.JSONDecodeError, ValueError, KeyError):
        return False


def get_server_url() -> str:
    """Get the configured server URL, or the default."""
    try:
        if CONFIG_FILE.exists():
            config = json.loads(CONFIG_FILE.read_text(encoding="utf-8"))
            url = config.get("serverUrl")
            if url:
                return str(url)
    except (json.JSONDecodeError, OSError):
        pass
    return DEFAULT_SERVER_URL


def save_server_url(url: str) -> None:
    """Save the server URL for future use."""
    _ensure_dir()
    config: dict[str, object] = {}
    try:
        if CONFIG_FILE.exists():
            config = json.loads(CONFIG_FILE.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, OSError):
        pass
    config["serverUrl"] = url
    CONFIG_FILE.write_text(json.dumps(config, indent=2), encoding="utf-8")
