import os
import re
import sys
import subprocess
from pathlib import Path

import pytest


TOKEN = os.getenv("VOXYGEN_TOKEN")

pytestmark = pytest.mark.skipif(
    not TOKEN,
    reason="Set VOXYGEN_TOKEN env variable to run integration tests",
)


def _python_root() -> Path:
    # python/test/test_examples.py -> python/
    return Path(__file__).resolve().parents[1]


def _examples_dir() -> Path:
    return _python_root() / "examples"


def _read_example(name: str) -> str:
    p = _examples_dir() / name
    if not p.exists():
        pytest.fail(f"Missing example file: {p}")
    return p.read_text(encoding="utf-8")


def _run_example_code(code: str, tmp_path: Path) -> subprocess.CompletedProcess:
    """
    Run provided python code in a subprocess, with working dir = tmp_path.
    """
    env = os.environ.copy()
    # Ensure the local syntHTTPclient.py is importable
    env["PYTHONPATH"] = str(_python_root()) + os.pathsep + env.get("PYTHONPATH", "") + "examples"

    return subprocess.run(
        [sys.executable, "-c", code],
        cwd=str(tmp_path),
        capture_output=True,
        text=True,
        env=env,
    )


def _patch_token(code: str) -> str:
    """
    Replace token="YOUR_TOKEN" with the real token in example scripts.
    Handles both single and double quotes.
    """
    # token="YOUR_TOKEN" / token='YOUR_TOKEN'
    code = re.sub(
        r'token\s*=\s*([\'"])YOUR_TOKEN\1',
        lambda m: f'token={m.group(1)}{TOKEN}{m.group(1)}',
        code,
    )
    return code


def test_example_streaming(tmp_path: Path):
    code = _read_example("streaming.py")
    code = _patch_token(code)

    p = _run_example_code(code, tmp_path)
    assert p.returncode == 0, f"STDOUT:\n{p.stdout}\nSTDERR:\n{p.stderr}"

    # Expect at least one "received chunk..." line
    lines = [ln for ln in p.stdout.splitlines() if "received chunk of audio data:" in ln]
    assert lines, f"No chunk output detected.\nSTDOUT:\n{p.stdout}\nSTDERR:\n{p.stderr}"


def test_example_audio_file_response_creates_output_wav(tmp_path: Path):
    code = _read_example("audio-file-response.py")
    code = _patch_token(code)

    p = _run_example_code(code, tmp_path)
    assert p.returncode == 0, f"STDOUT:\n{p.stdout}\nSTDERR:\n{p.stderr}"

    out = tmp_path / "output.wav"
    assert out.exists(), f"output.wav was not created.\nSTDOUT:\n{p.stdout}\nSTDERR:\n{p.stderr}"
    assert out.stat().st_size > 500, f"output.wav seems too small: {out.stat().st_size} bytes"
    assert "Audio saved to output.wav" in p.stdout


def test_example_json_response_prints_duration_and_saves_wav(tmp_path: Path):
    code = _read_example("json-response.py")
    code = _patch_token(code)

    p = _run_example_code(code, tmp_path)
    assert p.returncode == 0, f"STDOUT:\n{p.stdout}\nSTDERR:\n{p.stderr}"

    # Expected prints from your example
    assert "Duration:" in p.stdout
    assert "Warnings:" in p.stdout
    assert "Events (first 5):" in p.stdout

    # It should usually save output.wav if url is present (as in your code)
    out = tmp_path / "output.wav"
    assert out.exists(), f"output.wav was not created.\nSTDOUT:\n{p.stdout}\nSTDERR:\n{p.stderr}"
    assert out.stat().st_size > 500, f"output.wav seems too small: {out.stat().st_size} bytes"
    assert "Audio saved to output.wav" in p.stdout


def test_example_info_prints_available_voices(tmp_path: Path):
    code = _read_example("info.py")
    code = _patch_token(code)

    p = _run_example_code(code, tmp_path)
    assert p.returncode == 0, f"STDOUT:\n{p.stdout}\nSTDERR:\n{p.stderr}"

    assert "Available voices:" in p.stdout
    # Should list at least one voice name line after the header
    lines = [ln.strip() for ln in p.stdout.splitlines()]
    idx = lines.index("Available voices:")
    assert any(ln for ln in lines[idx + 1 :] if ln), f"No voices printed.\nSTDOUT:\n{p.stdout}\nSTDERR:\n{p.stderr}"
