#!/usr/bin/env python3
"""Transport shim Repliz API via `openssl s_client` (Workaround 21 Sep 2026).

GEJALA: dari host ini TLS ke api.repliz.com GAGAL konsisten untuk curl & Python
urllib/ssl (`SSL: UNEXPECTED_EOF_WHILE_READING`, curl exit 35, node fetch failed)
— 0/6 sukses. Tapi handshake + HTTP/1.1 lewat `openssl s_client` CLI SUKSES
(5/6; 1x flake jaringan) dan server balas 200. Indikasi TLS-fingerprint/DPI:
middlebox nolak ClientHello curl/OpenSSL-library, tapi lolos ClientHello CLI.

Solusi: kirim request HTTP/1.1 mentah lewat stdio `openssl s_client -quiet`,
parse response manual, dengan retry (5 percobaan) untuk antisipasi flake.

Pakai:
    from repliz_openssl_transport import install, api_request
    install()            # monkeypatch ReplizClient._request → transparan
    client.get_schedules(page=1, limit=100)
"""
import json
import subprocess
import tempfile
import time

HOST = "api.repliz.com"
PORT = 443
TRIES = 6
TIMEOUT = 60


def _http_raw(method: str, path: str, headers: dict, body: bytes = None) -> bytes:
    """Satu percobaan: kirim request lewat openssl s_client, balikin bytes response."""
    lines = [f"{method} {path} HTTP/1.1", f"Host: {HOST}"]
    for k, v in headers.items():
        lines.append(f"{k}: {v}")
    if body is not None:
        lines.append(f"Content-Length: {len(body)}")
    lines.append("Connection: close")
    req = ("\r\n".join(lines) + "\r\n\r\n").encode() + (body or b"")

    with tempfile.TemporaryFile() as errf:
        p = subprocess.Popen(
            ["openssl", "s_client", "-quiet", "-connect", f"{HOST}:{PORT}",
             "-servername", HOST],
            stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=errf)
        try:
            out, _ = p.communicate(req, timeout=TIMEOUT)
        except subprocess.TimeoutExpired:
            p.kill()
            out, _ = p.communicate()
            raise RuntimeError("openssl s_client timeout")
    if not out.startswith(b"HTTP/"):
        raise RuntimeError(f"response tidak valid ({len(out)} bytes)")
    return out


def _parse(raw: bytes):
    """Parse raw HTTP/1.1 response → (status, headers dict, body bytes)."""
    head, _, rest = raw.partition(b"\r\n\r\n")
    lines = head.decode("utf-8", "replace").split("\r\n")
    status = int(lines[0].split()[1])
    hdrs = {}
    for ln in lines[1:]:
        if ":" in ln:
            k, v = ln.split(":", 1)
            hdrs[k.strip().lower()] = v.strip()
    if hdrs.get("transfer-encoding", "").lower() == "chunked":
        buf, out = rest, b""
        while True:
            pos = buf.find(b"\r\n")
            if pos < 0:
                break
            size = int(buf[:pos].split(b";")[0], 16)
            if size == 0:
                break
            out += buf[pos + 2:pos + 2 + size]
            buf = buf[pos + 2 + size + 2:]
        rest = out
    elif "content-length" in hdrs:
        rest = rest[:int(hdrs["content-length"])]
    return status, hdrs, rest


def raw_request_retry(method: str, path: str, headers: dict, body: bytes = None,
                      tries: int = TRIES):
    """Request HTTP mentah lewat openssl s_client + retry → (status, headers, body)."""
    last = None
    for attempt in range(1, tries + 1):
        try:
            status, hdrs, payload = _parse(_http_raw(method, path, headers, body))
            return status, hdrs, payload
        except Exception as e:  # noqa: BLE001 — flake jaringan/DPI → retry
            last = e
            time.sleep(1.5 * attempt)
    raise RuntimeError(f"openssl transport gagal {tries}x {method} {path}: {last}")


def api_request(method: str, endpoint: str, data: dict = None, raw: bool = False):
    """Request ke Repliz API lewat openssl transport. Return dict/str."""
    from repliz_client import HEADERS, ReplizError
    body = json.dumps(data).encode() if data else None
    status, _, payload = raw_request_retry(method, endpoint, dict(HEADERS), body)
    if status == 204:
        return {"success": True}
    if status >= 400:
        raise ReplizError(f"HTTP {status} on {method} {endpoint}: "
                          f"{payload.decode('utf-8', 'replace')[:500]}")
    if raw:
        return payload.decode()
    return json.loads(payload)


def install(verbose: bool = True):
    """Monkeypatch ReplizClient._request supaya semua method pakai transport ini."""
    import repliz_client as rc

    def _request(self, method: str, endpoint: str, data: dict = None, raw: bool = False):
        return api_request(method, endpoint, data, raw)

    rc.ReplizClient._request = _request
    if verbose:
        print(f"[transport] ReplizClient._request → openssl s_client shim "
              f"({HOST}:{PORT}, {TRIES} percobaan)")
    return rc


if __name__ == "__main__":
    install()
    r = api_request("GET", "/public/schedule?page=1&limit=1")
    print("totalDocs:", r.get("totalDocs"), "| docs:", len(r.get("docs", [])))
