# mini app skeleton: copy and adapt this for a new quota dashboard.
# Substitute your provider's auth endpoint and field semantics — see
# /root/.hermes/skills/productivity/quota-dashboard-builder/references/minimax-opencode-integration.md
# for the two providers already shipped.
"""
Single-file Python quota viewer.

Run with: ./venv/bin/python app.py
Or via systemd, see nginx-reverse-proxy-skill for HTTPS fronting.
"""
from __future__ import annotations

import argparse
import json
import os
import re
from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone, timedelta
from pathlib import Path
from typing import Any

import httpx
import uvicorn
from fastapi import FastAPI
from fastapi.responses import FileResponse

CONFIG_PATH = Path(os.environ.get("MINIQUOTA_CONFIG", "/root/miniquota/config.json"))
STATIC_DIR = Path(__file__).resolve().parent / "static"
PORT = 8788


# ---------- Configuration --------------------------------------------------

@dataclass
class Window:
    label: str
    used: float
    remaining: float
    total: float
    unit: str
    reset_at: str
    reset_in_sec: int

    def to_dict(self) -> dict:
        return asdict(self)


@dataclass
class AccountResult:
    index: int
    name: str
    success: bool
    updated_at: str
    windows: list[Window] = field(default_factory=list)
    error: str = ""
    workspace: str = ""

    def to_dict(self) -> dict:
        d = {"index": self.index, "name": self.name,
             "success": self.success, "updated_at": self.updated_at}
        if self.workspace: d["workspace"] = self.workspace
        if self.error: d["error"] = self.error
        if self.windows: d["windows"] = [w.to_dict() for w in self.windows]
        return d


def load_config() -> dict[str, Any]:
    if not CONFIG_PATH.exists():
        return {}
    return json.loads(CONFIG_PATH.read_text(encoding="utf-8"))


def mask(s: str) -> str:
    """Mask a secret: first4...last4 or ****."""
    v = (s or "").strip()
    if not v:
        return ""
    if len(v) <= 8:
        return "****"
    return f"{v[:4]}…{v[-4:]}"


# ---------- Provider fetchers ---------------------------------------------
#
# Each provider has ONE async fetch function with the signature:
#     async def fetch_<provider>(account: dict, index: int) -> AccountResult
# and ONE HTTP endpoint:
#     GET /api/<provider>/quota -> list[dict]
#
# Add provider-specific quirks below, following the dataclass to_dict contract.

async def fetch_<provider>(account: dict, index: int) -> AccountResult:
    """Replace this with your provider's auth call. See references/ for examples."""
    now = datetime.now(timezone.utc)
    ts = now.isoformat().replace("+00:00", "Z")
    return AccountResult(
        index=index,
        name=account.get("name", f"account-{index}"),
        success=False,
        updated_at=ts,
        error="not implemented — copy one from references/minimax-opencode-integration.md",
    )


# ---------- FastAPI app ----------------------------------------------------

app = FastAPI(title="miniquota", version="0.1.0")


@app.get("/", include_in_schema=False)
async def index() -> FileResponse:
    return FileResponse(STATIC_DIR / "index.html")


@app.get("/api/health")
async def health() -> dict:
    return {"status": "ok"}


@app.get("/api/<provider>/quota")
async def quota() -> list[dict]:
    cfg = load_config()
    accounts = cfg.get("<provider>_accounts", []) or []
    out: list[dict] = []
    for i, acct in enumerate(accounts):
        r = await fetch_<provider>(acct, i)
        out.append(r.to_dict())
    return out


@app.get("/api/config")
async def config_status() -> dict:
    cfg = load_config()
    return {
        "<provider>_accounts": [
            {
                "name": a.get("name", ""),
                "configured": bool((a.get("credential_field") or "").strip()),
                "credential_masked": mask(a.get("credential_field", "")),
            }
            for a in cfg.get("<provider>_accounts", []) or []
        ]
    }


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--host", default=os.environ.get("MINIQUOTA_HOST", "127.0.0.1"))
    parser.add_argument("--port", type=int, default=int(os.environ.get("MINIQUOTA_PORT", PORT)))
    args = parser.parse_args()
    uvicorn.run("app:app", host=args.host, port=args.port, reload=False)


if __name__ == "__main__":
    main()
