#!/usr/bin/env python3
"""Real loopback HTTP checks with isolated temporary state. No external calls."""
from pathlib import Path
from tempfile import TemporaryDirectory
import re
import subprocess
import sys
import urllib.error
from urllib.parse import urlencode
from urllib.request import urlopen
from receiver import initialize, inspect, token


def request(port, values):
    url = f"http://127.0.0.1:{port}/call-event?" + urlencode(values)
    try:
        response = urlopen(url, timeout=5)
    except urllib.error.HTTPError as error:
        response = error
    with response:
        return response.status, response.read().decode().strip()


def start(directory):
    process = subprocess.Popen(
        [sys.executable, "-B", str(Path(__file__).with_name("receiver.py")),
         "serve", "--state", str(directory), "--port", "0"],
        stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    line = process.stdout.readline()
    match = re.fullmatch(r"Loopback lab listening on 127\.0\.0\.1:(\d+); Ctrl\+C stops it\.\n", line)
    if not match:
        stop(process)
        raise AssertionError("Receiver process did not report its loopback listener.")
    return process, int(match.group(1))


def stop(process):
    process.terminate()
    try:
        process.communicate(timeout=5)
    except subprocess.TimeoutExpired:
        process.kill()
        process.communicate()


with TemporaryDirectory(prefix="vicigeek-call-url-") as scratch:
    directory = initialize(Path(scratch) / "private-state")
    event = dict(source="TRAINING_A", event="dispo", call_id="1700000000.42", lead_id="900001", dispo="SALE", token=token(directory))
    process, port = start(directory)
    try:
        cases = [
            ("new event", event, 201, "stored"),
            ("identical replay", event, 200, "duplicate"),
            ("wrong token", {**event, "token": "not-the-token"}, 403, "rejected-token"),
            ("missing identity", {k:v for k,v in event.items() if k!="call_id"}, 400, "missing-or-extra-field"),
            ("unexpanded variable", {**event, "call_id": "--A--uniqueid--B--"}, 400, "invalid-event"),
            ("changed same-key event", {**event, "dispo": "CALLBK"}, 409, "conflict"),
        ]
        for label, values, expected_status, expected_text in cases:
            code, body = request(port, values)
            assert code == expected_status and expected_text in body, (label, code, body)
            print(f"PASS {label}: HTTP {code} {expected_text}")
        assert len(inspect(directory)) == 1
    finally:
        stop(process)
    process, port = start(directory)
    try:
        code, body = request(port, event)
        assert code == 200 and "duplicate" in body and len(inspect(directory)) == 1
        print("PASS receiver restart: replay remains duplicate; ledger still has one row")
    finally:
        stop(process)
print("PASS 7 loopback HTTP cases; no VICIdial event or CRM request was sent")
