"""Tests for image_converter module and image-input CLI flow."""

import argparse
import io
import json
import os
import tempfile
import unittest
from contextlib import redirect_stdout
from unittest.mock import MagicMock, patch

from PIL import Image


# ---------------------------------------------------------------------------
# is_image_file tests
# ---------------------------------------------------------------------------

class TestIsImageFile(unittest.TestCase):
    """Tests for image_converter.is_image_file()."""

    def setUp(self):
        from video_thumbnail_creator.image_converter import is_image_file
        self.is_image_file = is_image_file

    def test_positive_jpg(self):
        self.assertTrue(self.is_image_file("photo.jpg"))

    def test_positive_jpeg(self):
        self.assertTrue(self.is_image_file("photo.jpeg"))

    def test_positive_png(self):
        self.assertTrue(self.is_image_file("photo.png"))

    def test_positive_tiff(self):
        self.assertTrue(self.is_image_file("photo.tiff"))

    def test_positive_tif(self):
        self.assertTrue(self.is_image_file("photo.tif"))

    def test_positive_heic(self):
        self.assertTrue(self.is_image_file("photo.heic"))

    def test_positive_heif(self):
        self.assertTrue(self.is_image_file("photo.heif"))

    def test_negative_mp4(self):
        self.assertFalse(self.is_image_file("video.mp4"))

    def test_negative_mkv(self):
        self.assertFalse(self.is_image_file("video.mkv"))

    def test_negative_mov(self):
        self.assertFalse(self.is_image_file("video.mov"))

    def test_case_insensitive_jpg(self):
        self.assertTrue(self.is_image_file("PHOTO.JPG"))

    def test_case_insensitive_tiff(self):
        self.assertTrue(self.is_image_file("photo.TIFF"))

    def test_case_insensitive_heic(self):
        self.assertTrue(self.is_image_file("photo.Heic"))


# ---------------------------------------------------------------------------
# prepare_image_source tests
# ---------------------------------------------------------------------------

class TestPrepareImageSource(unittest.TestCase):
    """Tests for image_converter.prepare_image_source()."""

    def _make_jpeg(self, path: str, width: int = 100, height: int = 100) -> None:
        img = Image.new("RGB", (width, height), color=(100, 150, 200))
        img.save(path, "JPEG")

    def _make_png(self, path: str, width: int = 100, height: int = 100) -> None:
        img = Image.new("RGB", (width, height), color=(200, 100, 50))
        img.save(path, "PNG")

    def test_jpeg_passthrough_copies_file(self):
        from video_thumbnail_creator.image_converter import prepare_image_source

        with tempfile.TemporaryDirectory() as tmpdir:
            src = os.path.join(tmpdir, "photo.jpg")
            out = os.path.join(tmpdir, "output.jpg")
            self._make_jpeg(src)

            # Patch is_wide_gamut_image to return False (sRGB JPEG)
            with patch("video_thumbnail_creator.image_converter.is_wide_gamut_image", return_value=False):
                result = prepare_image_source(src, out)

            self.assertTrue(os.path.isabs(result))
            self.assertTrue(os.path.isfile(result))

    def test_png_converted_to_jpeg(self):
        from video_thumbnail_creator.image_converter import prepare_image_source

        with tempfile.TemporaryDirectory() as tmpdir:
            src = os.path.join(tmpdir, "photo.png")
            out = os.path.join(tmpdir, "output.jpg")
            self._make_png(src)

            # sips not available → falls through to Pillow
            with patch("video_thumbnail_creator.image_converter.shutil.which", return_value=None):
                result = prepare_image_source(src, out)

            self.assertTrue(os.path.isabs(result))
            self.assertTrue(os.path.isfile(result))
            with Image.open(result) as img:
                self.assertEqual(img.format, "JPEG")

    def test_missing_file_raises(self):
        from video_thumbnail_creator.image_converter import prepare_image_source

        with tempfile.TemporaryDirectory() as tmpdir:
            out = os.path.join(tmpdir, "output.jpg")
            with self.assertRaises(FileNotFoundError):
                prepare_image_source("/nonexistent/photo.jpg", out)

    def test_output_is_absolute_path(self):
        from video_thumbnail_creator.image_converter import prepare_image_source

        with tempfile.TemporaryDirectory() as tmpdir:
            src = os.path.join(tmpdir, "photo.jpg")
            out = os.path.join(tmpdir, "output.jpg")
            self._make_jpeg(src)

            with patch("video_thumbnail_creator.image_converter.is_wide_gamut_image", return_value=False):
                result = prepare_image_source(src, out)

            self.assertTrue(os.path.isabs(result))


# ---------------------------------------------------------------------------
# CLI: input_path argument and JSON output tests
# ---------------------------------------------------------------------------

class TestInputPathCLIArgument(unittest.TestCase):
    """Tests that the extract subcommand uses input_path instead of video_path."""

    def _build_parser(self):
        from video_thumbnail_creator.cli import _build_parser
        return _build_parser()

    def test_input_path_positional_argument(self):
        parser = self._build_parser()
        args = parser.parse_args(["extract", "photo.jpg"])
        self.assertEqual(args.input_path, "photo.jpg")

    def test_input_path_with_options(self):
        parser = self._build_parser()
        args = parser.parse_args(["extract", "photo.tiff", "--format", "poster"])
        self.assertEqual(args.input_path, "photo.tiff")
        self.assertEqual(args.format, "poster")


class TestEmitResultInputPath(unittest.TestCase):
    """Tests that _emit_result JSON uses 'input_path' key and supports source='image'."""

    def _emit(self, **kwargs):
        from video_thumbnail_creator.cli import _emit_result
        buf = io.StringIO()
        with redirect_stdout(buf):
            _emit_result(**kwargs)
        return json.loads(buf.getvalue())

    def test_json_uses_input_path_key(self):
        data = self._emit(
            poster_path="/tmp/poster.jpg",
            frame_index=5,
            mode="auto",
            reasoning="ok",
            input_path="/tmp/video.mp4",
            use_json=True,
        )
        self.assertIn("input_path", data)
        self.assertNotIn("video_path", data)

    def test_json_source_image(self):
        data = self._emit(
            poster_path="/tmp/poster.jpg",
            frame_index=-1,
            mode="manual",
            reasoning="Image file was used as source.",
            input_path="/tmp/photo.jpg",
            use_json=True,
            source="image",
        )
        self.assertEqual(data["source"], "image")
        self.assertEqual(data["frame_index"], -1)
        self.assertIn("input_path", data)

    def test_json_frame_index_minus_one_for_image(self):
        data = self._emit(
            poster_path="/tmp/poster.jpg",
            frame_index=-1,
            mode="auto",
            reasoning="Image file was used as source.",
            input_path="/tmp/photo.tiff",
            use_json=True,
            source="image",
        )
        self.assertEqual(data["frame_index"], -1)


if __name__ == "__main__":
    unittest.main()
