"""Dash mensile live Account 2, separata dalla Dash v2 corrente."""
from __future__ import annotations

import base64
import hmac
import json
import os
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.error import HTTPError
from urllib.parse import parse_qs, urlsplit
from urllib.request import Request, urlopen

import preview_server as dashboard
from live_adapter import adapt_live

PORT = int(os.environ.get("V2_MONTHLY_PORT", "5512"))
UPSTREAM = os.environ.get("V2_STATS_UPSTREAM", "http://127.0.0.1:5511")
AUTH_USER = os.environ.get("V2_STATS_USER", "")
AUTH_PASS = os.environ.get("V2_STATS_PASS", "")
STATIC = {
    "": ("index.html", "text/html; charset=utf-8"),
    "index": ("index.html", "text/html; charset=utf-8"),
    "index.html": ("index.html", "text/html; charset=utf-8"),
    "app.js": ("app.js", "application/javascript; charset=utf-8"),
    "charts.js": ("charts.js", "application/javascript; charset=utf-8"),
    "style.css": ("style.css", "text/css; charset=utf-8"),
}


def _auth_header():
    token = base64.b64encode(f"{AUTH_USER}:{AUTH_PASS}".encode()).decode()
    return f"Basic {token}"


def _fetch_snapshot():
    request = Request(f"{UPSTREAM}/json", headers={"Authorization": _auth_header()})
    with urlopen(request, timeout=35) as response:
        return json.load(response)


def _live_model(snapshot, view, month, alignment):
    dashboard.SNAPSHOT = snapshot
    dashboard.CURRENT_MONTH = snapshot["generated_at"][:7]
    dashboard.adapt = adapt_live
    dashboard.model.cache_clear()
    return dashboard.model(view, month or dashboard.CURRENT_MONTH, alignment)


class Handler(BaseHTTPRequestHandler):
    def log_message(self, *_):
        pass

    def _authorized(self):
        return not AUTH_PASS or hmac.compare_digest(self.headers.get("Authorization", ""), _auth_header())

    def _send(self, status, body, content_type="text/plain", attachment=None, location=None):
        self.send_response(status)
        self.send_header("Content-Type", content_type)
        self.send_header("Content-Length", str(len(body)))
        self.send_header("Cache-Control", "no-store")
        self.send_header("X-Content-Type-Options", "nosniff")
        if attachment:
            self.send_header("Content-Disposition", f'attachment; filename="{attachment}"')
        if location:
            self.send_header("Location", location)
        self.end_headers()
        self.wfile.write(body)

    def _unauthorized(self):
        self.send_response(401)
        self.send_header("WWW-Authenticate", 'Basic realm="v2-stats"')
        self.send_header("Content-Length", "0")
        self.end_headers()

    def _proxy_review(self):
        body = None
        if self.command == "POST":
            body = self.rfile.read(int(self.headers.get("Content-Length", "0")))
        headers = {"Authorization": _auth_header()}
        if self.headers.get("Content-Type"):
            headers["Content-Type"] = self.headers["Content-Type"]
        request = Request(f"{UPSTREAM}{self.path}", data=body, headers=headers, method=self.command)
        try:
            response = urlopen(request, timeout=40)
        except HTTPError as exc:
            response = exc
        payload = response.read()
        return self._send(response.status, payload, response.headers.get("Content-Type", "text/html; charset=utf-8"), location=response.headers.get("Location"))

    def do_GET(self):
        if not self._authorized():
            return self._unauthorized()
        parsed = urlsplit(self.path)
        if "/review" in parsed.path.rstrip("/"):
            return self._proxy_review()
        leaf = parsed.path.rsplit("/", 1)[-1]
        if leaf in STATIC:
            name, kind = STATIC[leaf]
            if name == "index.html" and parsed.path != "/" and not parsed.path.endswith("/"):
                return self._send(308, b"", location=parsed.path + "/")
            body = (dashboard.ROOT / name).read_bytes()
            if name == "index.html":
                body = body.replace(b"ANTEPRIMA LOCALE \xc2\xb7 BLOCCO 4", b"OPERATIVA \xc2\xb7 DATI LIVE ACCOUNT 2")
                body = body.replace(b"Nessun collegamento al trading.", b"Sola lettura: nessun comando verso il trading.")
                body = body.replace(b"Saldo e posizioni sono quelli acquisiti nello snapshot, <strong>non valori live attuali</strong>.", b"Saldo e posizioni sono aggiornati dalla Dash v2 di Account 2.")
                body = body.replace(b"Rilettura ogni 30s \xc2\xb7 stessa fotografia", b"Aggiornamento automatico ogni 30s")
            return self._send(200, body, kind)
        if leaf == "health":
            snapshot = _fetch_snapshot()
            body = json.dumps({"status": "ok", "mode": "live", "upstream_generated_at": snapshot["generated_at"]}).encode()
            return self._send(200, body, "application/json")
        if leaf not in {"report", "export.csv"}:
            return self._send(404, b"Not found")
        params = parse_qs(parsed.query, keep_blank_values=True)
        if any(len(values) != 1 for values in params.values()):
            return self._send(400, b"Duplicate query parameters")
        try:
            snapshot = _fetch_snapshot()
            data = _live_model(snapshot, params.get("view", ["all"])[0], params.get("month", [None])[0], params.get("alignment", ["full"])[0])
        except (ValueError, KeyError, OverflowError):
            return self._send(400, b"Periodo o vista non validi")
        if leaf == "export.csv":
            scope = "confronto-mesi-" + data["alignment"] if data["view"] == "compare" else ("storico" if data["view"] == "all" else data["month"])
            return self._send(200, dashboard.export_csv(data), "text/csv; charset=utf-8", f"dash-v2-{scope}-live.csv")
        body = json.dumps(data, ensure_ascii=False, allow_nan=False).encode("utf-8")
        return self._send(200, body, "application/json; charset=utf-8")

    def do_POST(self):
        if not self._authorized():
            return self._unauthorized()
        if "/review/" in urlsplit(self.path).path:
            return self._proxy_review()
        return self._send(405, b"Method not allowed")


def main():
    server = ThreadingHTTPServer(("127.0.0.1", PORT), Handler)
    print(f"Dash mensile live Account 2 su 127.0.0.1:{PORT}", flush=True)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        pass
    finally:
        server.server_close()


if __name__ == "__main__":
    main()
