import asyncio
import mimetypes
import os
import statistics
import sys
import time
from pathlib import Path

import aiohttp
import pytest

from clarabot_nano.picoture import PICOTURE_JAR
from clarabot_nano.utility.path.java import java_compatible_absolute_path
from clarabot_nano_tests.picoture.resources import INPUT_ROOT, OUTPUT_ROOT
from clarabot_nano_tests.testing.file import walk_dir_for_relative_paths
from clarabot_nano_tests.testing.process import popen


@pytest.mark.asyncio
async def test_picoture_output(dev_nano_root_dir):
    assert PICOTURE_JAR.is_file(), str(PICOTURE_JAR)
    java_exe = Path(dev_nano_root_dir, "deps", "jre", "bin", "java.exe" if sys.platform.startswith("win") else "java")
    assert java_exe.is_file(), str(java_exe)
    file_paths = set(walk_dir_for_relative_paths(INPUT_ROOT))
    for out_path in walk_dir_for_relative_paths(OUTPUT_ROOT):
        assert os.path.splitext(out_path)[0] in file_paths, out_path
    port = 7072
    version_url = f"http://127.0.0.1:{port}/version"
    picture_url = f"http://127.0.0.1:{port}/picture"
    async with aiohttp.ClientSession() as session:
        with popen(
            [
                java_compatible_absolute_path(java_exe),
                "-jar",
                java_compatible_absolute_path(PICOTURE_JAR),
                "--host",
                "127.0.0.1",
                "--port",
                str(port),
            ]
        ) as proc:
            # wait for picoture to start
            for _ in range(50):
                assert proc.poll() is None
                try:
                    async with session.get(version_url) as resp:
                        if resp.status == 200:
                            text = await resp.text()
                            assert text.startswith("Picoture "), text
                            break
                except aiohttp.ClientConnectorError:
                    pass
                await asyncio.sleep(0.25)
            else:
                assert False, "Picoture did not start in time"
            # check or generate reference output
            times = []
            for file_path in sorted(file_paths):
                in_path = INPUT_ROOT / file_path
                out_path = OUTPUT_ROOT / f"{file_path}.jpg"
                t = time.perf_counter()
                headers = {}
                mime_type = mimetypes.guess_type(in_path)[0]
                if mime_type:
                    headers["Content-Type"] = mime_type
                async with session.post(picture_url, data=in_path.read_bytes(), headers=headers) as resp:
                    times.append(time.perf_counter() - t)
                    generated_output = await resp.read()
                    if resp.status == 200:
                        pass
                    elif resp.status == 415:  # unsupported media type
                        assert generated_output == b"", generated_output
                    else:
                        assert False, f"Unexpected status: {resp.status}\n{generated_output}"
                    if out_path.exists():
                        if generated_output != out_path.read_bytes():
                            (out_path.parent / f"ERR_{out_path.name}").write_bytes(generated_output)
                            assert False, f"Mismatching generated and reference data: {file_path}"
                    else:
                        out_path.parent.mkdir(parents=True, exist_ok=True)
                        out_path.write_bytes(generated_output)
    # some performance checking
    assert statistics.median(times) < 0.1, str(times)
    assert 1.5 < max(times) < 10.0, str(times)  # 4K webp is very slow
