"""Supabase Storage — the WRITABLE shared file store for jarvis-tools.

A service account can't write to a personal Google Drive (no quota), so this is
the write layer: Jarvis/any AI on any device can save, read, list, and delete
files here, and they sync everywhere. Works from the cloud connector (plain
HTTPS, no OAuth). Files live in the 'jarvis-files' bucket of Ahmed's Supabase.

Env: SUPABASE_URL, SUPABASE_SECRET (the service_role key).
(Reading Ahmed's Google Drive uploads still goes through the drive_* tools.)
"""
from __future__ import annotations

import json
import mimetypes
import os
import urllib.error
import urllib.parse
import urllib.request

BUCKET = os.environ.get("STORAGE_BUCKET", "jarvis-files")


def _base() -> str:
    return os.environ.get("SUPABASE_URL", "").rstrip("/")


def _key() -> str:
    return os.environ.get("SUPABASE_SECRET", "")


def configured() -> bool:
    return bool(_base() and _key())


def _headers(extra: dict | None = None) -> dict:
    h = {"Authorization": f"Bearer {_key()}", "apikey": _key()}
    if extra:
        h.update(extra)
    return h


def _do(method: str, path: str, body: bytes | None = None,
        headers: dict | None = None) -> bytes:
    req = urllib.request.Request(f"{_base()}/storage/v1{path}", data=body,
                                method=method)
    for k, v in _headers(headers).items():
        req.add_header(k, v)
    try:
        with urllib.request.urlopen(req, timeout=30) as r:
            return r.read()
    except urllib.error.HTTPError as e:
        raise RuntimeError(f"HTTP {e.code}: "
                           f"{e.read()[:200].decode('utf-8', 'ignore')}")


def _ensure_bucket() -> None:
    try:
        _do("POST", "/bucket",
            json.dumps({"id": BUCKET, "name": BUCKET, "public": False}).encode(),
            {"Content-Type": "application/json"})
    except Exception as e:  # noqa: BLE001 — already-exists is fine
        if "exist" not in str(e).lower() and "duplicate" not in str(e).lower():
            pass


# Supabase Storage keys must be ASCII from a limited set (rejects '%' and any
# non-ASCII, e.g. Arabic filenames → InvalidKey). Reversibly escape the display
# name into a safe key: non-keep bytes → _<hexlo>. Callers use the real name.
_KEEP = frozenset(
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-() ")
_HEX = frozenset("0123456789abcdef")


def _enc_key(name: str) -> str:
    name = str(name).strip().lstrip("/")
    return "".join(chr(b) if chr(b) in _KEEP else f"_{b:02x}"
                   for b in name.encode("utf-8"))


def _dec_name(key: str) -> str:
    b = bytearray()
    i, n = 0, len(key)
    while i < n:
        if key[i] == "_" and i + 3 <= n and key[i+1] in _HEX and key[i+2] in _HEX:
            b.append(int(key[i+1:i+3], 16))
            i += 3
        else:
            b.append(ord(key[i]) & 0xFF)
            i += 1
    return b.decode("utf-8", "replace")


def write(name: str, content: str) -> str:
    name = str(name).strip().lstrip("/")
    if not name:
        return "storage_write failed: need a file name."
    _ensure_bucket()
    body = content.encode("utf-8") if isinstance(content, str) else content
    mime = mimetypes.guess_type(name)[0] or "text/plain"
    try:
        _do("POST", f"/object/{BUCKET}/{urllib.parse.quote(_enc_key(name), safe='/')}", body,
            {"Content-Type": mime, "x-upsert": "true"})
        return f"Saved {name} to shared storage ({len(body)} bytes)."
    except Exception as e:  # noqa: BLE001
        return f"storage_write failed: {str(e)[:180]}"


def read(name: str) -> str:
    name = str(name).strip().lstrip("/")
    try:
        data = _do("GET", f"/object/{BUCKET}/{urllib.parse.quote(_enc_key(name), safe='/')}")
        txt = data.decode("utf-8", "ignore")
        return f"{name}:\n{txt[:7000]}" + (" …[truncated]" if len(txt) > 7000 else "")
    except Exception as e:  # noqa: BLE001
        return f"storage_read failed: {str(e)[:180]}"


def list_files() -> str:
    try:
        data = _do("POST", f"/object/list/{BUCKET}",
                   json.dumps({"prefix": "", "limit": 100,
                               "sortBy": {"column": "name", "order": "asc"}}).encode(),
                   {"Content-Type": "application/json"})
        items = json.loads(data)
        if not items:
            return "Shared storage is empty."
        lines = [f"- {_dec_name(i['name'])} "
                 f"({(i.get('metadata') or {}).get('size', '?')} bytes)"
                 for i in items if i.get("name")]
        return f"{len(lines)} file(s) in shared storage:\n" + "\n".join(lines)
    except Exception as e:  # noqa: BLE001
        return f"storage_list failed: {str(e)[:180]}"


def delete(name: str) -> str:
    name = str(name).strip().lstrip("/")
    try:
        _do("DELETE", f"/object/{BUCKET}/{urllib.parse.quote(_enc_key(name), safe='/')}")
        return f"Deleted {name} from shared storage."
    except Exception as e:  # noqa: BLE001
        return f"storage_delete failed: {str(e)[:180]}"
