#!/usr/bin/env python3
"""
http_test.py — test the HTTP listener mode with curl-like requests.

Starts nsigner in HTTP mode, sends requests via urllib, and verifies
the responses.
"""
import json
import os
import subprocess
import sys
import time
import urllib.request

NSIGNER = "./build/nsigner"
PAD_DIR = "/media/user/Music/pads"
PAD_SPEC = "333e9902db839d9d"
MNEMONIC_FILE = ".test_mnemonic"
MNEMONIC_TMP = ".test_mnemonic_http.tmp"
PORT = 11111


def main():
    # Reset pad offset
    state_path = f"{PAD_DIR}/333e9902db839d9d7f1f6aaa30f392a77c9abd011dd6274d9d3cf167361a789e.state"
    with open(state_path, "w") as f:
        f.write("offset=32\n")

    # Prepare mnemonic temp file
    with open(MNEMONIC_FILE) as f:
        mnemonic = f.read().strip()
    with open(MNEMONIC_TMP, "w") as f:
        f.write(mnemonic + "\n")

    # Start nsigner in HTTP mode
    shell_cmd = (
        f"exec 3<{MNEMONIC_TMP} 2>/dev/null; "
        f"exec {NSIGNER} --listen http:127.0.0.1:{PORT} --mnemonic-fd 3 "
        f"--otp-pad-dir {PAD_DIR} --otp-pad {PAD_SPEC} "
        f"--otp-allow-blkback --allow-all"
    )
    proc = subprocess.Popen(
        ["bash", "-c", shell_cmd],
        stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    )
    time.sleep(2.0)  # let the signer start

    if proc.poll() is not None:
        err = proc.stderr.read().decode()
        print(f"ERROR: nsigner exited early (code {proc.returncode})")
        print(f"stderr: {err}")
        try:
            os.unlink(MNEMONIC_TMP)
        except OSError:
            pass
        return 1

    try:
        url = f"http://127.0.0.1:{PORT}/"

        # Test 1: get_public_key
        print("=== Test 1: get_public_key via HTTP ===")
        req_data = json.dumps({
            "id": "1",
            "method": "get_public_key",
            "params": [{"role": "main"}],
        }).encode()
        req = urllib.request.Request(url, data=req_data,
                                      headers={"Content-Type": "application/json"})
        with urllib.request.urlopen(req, timeout=5) as resp:
            result = json.loads(resp.read().decode())
        print(f"Response: {json.dumps(result)[:120]}...")
        if "result" not in result:
            print("ERROR: no result in get_public_key response")
            return 1
        pubkey = result["result"].strip('"')
        print(f"Public key: {pubkey}")

        # Test 2: otp_encrypt
        print("\n=== Test 2: otp_encrypt via HTTP ===")
        import base64
        pt_b64 = base64.b64encode(b"Hello, OTP via HTTP!").decode()
        req_data = json.dumps({
            "id": "2",
            "method": "otp_encrypt",
            "params": [pt_b64, {"encoding": "ascii"}],
        }).encode()
        req = urllib.request.Request(url, data=req_data,
                                      headers={"Content-Type": "application/json"})
        with urllib.request.urlopen(req, timeout=5) as resp:
            result = json.loads(resp.read().decode())
        print(f"Response: {json.dumps(result)[:200]}...")
        if "result" not in result:
            print("ERROR: no result in otp_encrypt response")
            return 1
        enc_result = json.loads(result["result"])
        ciphertext = enc_result["ciphertext"]
        print(f"Pad offset: {enc_result['pad_offset_before']} -> {enc_result['pad_offset_after']}")
        print(f"Ciphertext (first 60 chars): {ciphertext[:60]}...")

        # Test 3: otp_decrypt
        print("\n=== Test 3: otp_decrypt via HTTP ===")
        req_data = json.dumps({
            "id": "3",
            "method": "otp_decrypt",
            "params": [ciphertext, {"encoding": "ascii"}],
        }).encode()
        req = urllib.request.Request(url, data=req_data,
                                      headers={"Content-Type": "application/json"})
        with urllib.request.urlopen(req, timeout=5) as resp:
            result = json.loads(resp.read().decode())
        print(f"Response: {json.dumps(result)[:200]}...")
        if "result" not in result:
            print("ERROR: no result in otp_decrypt response")
            return 1
        dec_result = json.loads(result["result"])
        recovered = base64.b64decode(dec_result["plaintext"]).decode()
        print(f"Recovered plaintext: {recovered}")

        if recovered == "Hello, OTP via HTTP!":
            print("\n=== HTTP ROUND-TRIP SUCCESS ===")
            return 0
        else:
            print("\n=== HTTP ROUND-TRIP FAILED ===")
            print(f"Expected: Hello, OTP via HTTP!")
            print(f"Got:      {recovered}")
            return 1
    finally:
        proc.terminate()
        try:
            proc.wait(timeout=3)
        except subprocess.TimeoutExpired:
            proc.kill()
        try:
            os.unlink(MNEMONIC_TMP)
        except OSError:
            pass


if __name__ == "__main__":
    sys.exit(main())
