#
#            PySceneDetect: Python-Based Video Scene Detector
#   -------------------------------------------------------------------
#     [  Site:    https://scenedetect.com                           ]
#     [  Docs:    https://scenedetect.com/docs/                     ]
#     [  Github:  https://github.com/Breakthrough/PySceneDetect/    ]
#
# Copyright (C) 2020 Brandon Castellano <http://www.bcastell.com>.
# PySceneDetect is licensed under the BSD 3-Clause License; see the
# included LICENSE file, or visit one of the above pages for details.
#
"""PySceneDetect Test Configuration

This file includes all pytest configuration for running PySceneDetect's tests.

These tests rely on the files in the tests/resources/ folder in the "resources" branch of
the PySceneDetect git repository. These files can be checked out via git by running the
following from the root of the repo:

    git fetch --depth=1 https://github.com/Breakthrough/PySceneDetect.git refs/heads/resources:refs/remotes/origin/resources
    git checkout refs/remotes/origin/resources -- tests/resources/
    git reset

Note that currently these tests create some temporary files which are not yet cleaned up.
"""

# TODO: Properly cleanup temporary files.

import logging
import os
import typing as ty

import pytest

# Surface unhandled exceptions and KeyboardInterrupt as raw tracebacks during tests so pytest
# (and any debugger) sees the original failure instead of the logger-formatted output the CLI
# uses for end users. Read by `scenedetect.platform.DEBUG_MODE`. `setdefault` lets a developer
# override (e.g. `SCENEDETECT_DEBUG=` to mimic end-user behavior in a specific test run).
os.environ.setdefault("SCENEDETECT_DEBUG", "1")

#
# Helper Functions
#


def check_exists(path: ty.AnyStr) -> ty.AnyStr:
    """Returns the absolute path to a (relative) path of a file that
    should exist within the tests/ directory.

    Throws FileNotFoundError if the file could not be found.
    """
    if not os.path.exists(path):
        raise FileNotFoundError(
            f"""
Test video file ({path}) must be present to run test case. This file can be obtained by running the following commands from the root of the repository:

git fetch --depth=1 https://github.com/Breakthrough/PySceneDetect.git refs/heads/resources:refs/remotes/origin/resources
git checkout refs/remotes/origin/resources -- tests/resources/
git reset
"""
        )
    return path


#
# Pytest Hooks
#


def pytest_assertrepr_compare(op, left, right):
    if isinstance(left, str) and isinstance(right, str) and op == "in":
        return [
            "Did not find expected output in test.",
            "",
            "Expected to find:",
            "",
            *left.splitlines(),
            "",
            "Actual output:",
            "",
            *right.splitlines(),
        ]
    return []


#
# Test Case Fixtures
#


@pytest.fixture(autouse=True)
def no_logs_gte_error(caplog):
    """Ensure no log messages with error severity or higher were reported during test execution."""
    EXCLUDED_MODULES = set()
    yield
    errors = [
        record
        for record in caplog.get_records("call")
        if record.levelno >= logging.ERROR and record.module not in EXCLUDED_MODULES
    ]
    assert not errors, "Test failed due to presence of one or more logs with ERROR severity."


@pytest.fixture
def test_video_file() -> str:
    """Simple test video containing both fast cuts and fades/dissolves."""
    return check_exists("tests/resources/testvideo.mp4")


@pytest.fixture
def test_movie_clip() -> str:
    """Movie clip containing fast cuts."""
    return check_exists("tests/resources/goldeneye.mp4")


@pytest.fixture
def test_vfr_video() -> str:
    """Movie clip containing fast cut, but encoded as variable framerate."""
    return check_exists("tests/resources/goldeneye-vfr.mp4")


@pytest.fixture
def test_vfr_drop3_video() -> str:
    """Synthetic VFR video created from goldeneye.mp4 by dropping every 3rd frame.

    Frame pattern: keeps frames where (n+1) % 3 != 0 (i.e. drops frames 2,5,8,...).
    Resulting PTS durations alternate: 1001, 2002, 1001, 2002, ... (time_base=1/24000).
    Nominal fps: 24000/1001. Average fps: ~16 fps. Duration: ~10s, 160 frames.
    """
    return check_exists("tests/resources/goldeneye-vfr-drop3.mp4")


@pytest.fixture
def corrupt_video_file() -> str:
    """Video containing a corrupted frame causing a decode failure."""
    return check_exists("tests/resources/corrupt_frame.mp4")


@pytest.fixture
def rotated_video_file() -> str:
    """Video containing a corrupted frame causing a decode failure."""
    return check_exists("tests/resources/issue-134-rotate.mp4")


@pytest.fixture
def test_image_sequence() -> str:
    """Path to a short image sequence (from counter.mp4)."""
    return "tests/resources/counter/frame%03d.png"


@pytest.fixture
def test_fades_clip() -> str:
    """Clip containing fades in/out."""
    return check_exists("tests/resources/fades.mp4")
