"""Local HTTP and render-loop probe for Fugleramme d6baeef; no detector model."""
from contextlib import ExitStack
from datetime import datetime
import hashlib
import json
from pathlib import Path
import subprocess
import sys
import tempfile
from unittest.mock import patch

from PIL import Image
from fugleramme import api, fake, modes, service
from fugleramme.config import Config
from fugleramme.source import Unavailable


class StopLoop(Exception):
    pass


def url(server):
    return f'http://127.0.0.1:{server.server_address[1]}'


with tempfile.TemporaryDirectory(prefix='bird-frame-probe-') as directory:
    root = Path(directory)
    quiet = fake.serve([], '127.0.0.1', 0)
    down = fake.serve([], '127.0.0.1', 0, down=True)
    try:
        quiet_result = api.ApiSource(url(quiet)).species_since(0)
        assert quiet_result == []
        print('healthy_empty:', json.dumps(quiet_result))
        try:
            api.ApiSource(url(down)).species_since(0)
        except Unavailable as error:
            print('http_503:', type(error).__name__, str(error))
        else:
            raise AssertionError('503 became an empty result')
        checked = subprocess.run(
            [sys.executable, '-X', 'utf8', '-m', 'fugleramme.check',
             '--detector', url(quiet), '--config', str(root / 'check-settings.json')],
            text=True, encoding='utf-8', capture_output=True, check=False,
        )
        print('check_cli_exit:', checked.returncode)
        print(checked.stdout)
        assert checked.returncode == 0
    finally:
        quiet.shutdown()
        quiet.server_close()
        down.shutdown()
        down.server_close()

    birds = root / 'images' / 'classic' / 'birds'
    birds.mkdir(parents=True)
    # Synthetic artwork fixture; this probe makes no claims about real bird rendering.
    Image.new('RGBA', (120, 90), (40, 40, 40, 255)).save(birds / 'turdus-merula.png')
    rows = [fake.Detection(1, datetime.now().astimezone(), 'Turdus merula', 0.9, False)]
    live = fake.serve(rows, '127.0.0.1', 0)
    config = Config(images_dir=root / 'images', detector_url=url(live),
                    output_path=root / 'frame.png', host='127.0.0.1', port=0,
                    config_path=root / 'settings.json')
    hashes = []

    def tick(_seconds):
        hashes.append(hashlib.sha256(config.output_path.read_bytes()).hexdigest())
        if len(hashes) == 1:
            live.shutdown()
            live.server_close()
        if len(hashes) == 3:
            raise StopLoop

    with ExitStack() as stack:
        # Windows lacks the Unix diagnostic signal hook. Bypass that hook only.
        stack.enter_context(patch.object(service.faulthandler, 'register', create=True))
        stack.enter_context(patch.object(service.signal, 'SIGUSR1', 10, create=True))
        stack.enter_context(patch.object(service, 'init_panel', return_value=None))
        stack.enter_context(patch.object(service, 'serve', return_value=None))
        stack.enter_context(patch.object(service.updates, 'available', return_value=None))
        stack.enter_context(patch.object(api, '_TTL', 0))
        stack.enter_context(patch.object(service.time, 'sleep', side_effect=tick))
        rendered = stack.enter_context(patch.object(service.modes, 'render', wraps=modes.render))
        try:
            service.run(config)
        except StopLoop:
            pass
        finally:
            live.shutdown()
            live.server_close()
        assert rendered.call_count == 1
        assert len(hashes) == 3 and len(set(hashes)) == 1
        print(json.dumps({'render_calls': rendered.call_count, 'ticks': len(hashes),
                          'unique_frame_hashes': len(set(hashes)),
                          'api_cache_ttl': 0, 'panel': 'stubbed'}, indent=2))
