#!/usr/bin/env python3
"""
Tests for gen_image.py
Run: python -m pytest tests/test_gen_image.py -v
"""

import sys
import json
import base64
from pathlib import Path
from unittest.mock import patch, MagicMock

# Add parent to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))

from gen_image import preflight_check, encode_image, generate_image, make_request


class TestMakeRequest:
    """Tests for HTTP request helper."""

    @patch("gen_image.urllib.request.urlopen")
    def test_successful_get(self, mock_urlopen):
        """Should return data on successful GET."""
        mock_response = MagicMock()
        mock_response.status = 200
        mock_response.read.return_value = b'{"data": [{"id": "model1"}]}'
        mock_response.__enter__ = MagicMock(return_value=mock_response)
        mock_response.__exit__ = MagicMock(return_value=False)
        mock_urlopen.return_value = mock_response

        result = make_request("http://test.com/api")

        assert result["status"] == 200
        assert result["data"]["data"][0]["id"] == "model1"
        assert result["error"] is None

    @patch("gen_image.urllib.request.urlopen")
    def test_connection_error(self, mock_urlopen):
        """Should return error on connection failure."""
        from urllib.error import URLError

        mock_urlopen.side_effect = URLError("Connection refused")

        result = make_request("http://test.com/api")

        assert result["status"] == 0
        assert "Connection failed" in result["error"]


class TestPreflightCheck:
    """Tests for auth detection."""

    @patch("gen_image.make_request")
    def test_cliproxy_not_running(self, mock_request):
        """Should return error when CLIProxy is not running."""
        mock_request.return_value = {
            "status": 0,
            "data": None,
            "error": "Connection failed: Connection refused",
        }

        result = preflight_check()

        assert result["ready"] is False
        assert "CLIProxy không chạy" in result["error"]

    @patch("gen_image.make_request")
    def test_no_models_available(self, mock_request):
        """Should return error when no models are configured."""
        mock_request.return_value = {"status": 200, "data": {"data": []}, "error": None}

        result = preflight_check()

        assert result["ready"] is False
        assert "accounts" in result["error"]

    @patch("gen_image.make_request")
    def test_image_model_not_available(self, mock_request):
        """Should warn when image model is not in the list."""
        mock_request.return_value = {
            "status": 200,
            "data": {"data": [{"id": "gpt-5.2"}, {"id": "gpt-5.1-codex"}]},
            "error": None,
        }

        result = preflight_check()

        assert result["ready"] is False
        assert "không khả dụng" in result["error"]

    @patch("gen_image.make_request")
    def test_ready_when_model_available(self, mock_request):
        """Should be ready when image model is available."""
        mock_request.return_value = {
            "status": 200,
            "data": {"data": [{"id": "gemini-3-pro-image-preview"}, {"id": "gpt-5.2"}]},
            "error": None,
        }

        result = preflight_check()

        assert result["ready"] is True
        assert "gemini-3-pro-image-preview" in result["models"]


class TestEncodeImage:
    """Tests for image encoding."""

    def test_encode_nonexistent_file(self):
        """Should raise error for missing files."""
        try:
            encode_image("/nonexistent/path/image.jpg")
            assert False, "Should have raised FileNotFoundError"
        except FileNotFoundError:
            pass

    def test_encode_returns_data_url(self, tmp_path):
        """Should return valid data URL."""
        # Create a minimal JPEG
        test_image = tmp_path / "test.jpg"
        test_image.write_bytes(b"\xff\xd8\xff\xe0\x00\x10JFIF")

        result = encode_image(str(test_image))

        assert result.startswith("data:image/jpeg;base64,")


class TestGenerateImage:
    """Tests for image generation."""

    @patch("gen_image.make_request")
    def test_generate_success(self, mock_request, tmp_path):
        """Should save image on successful generation."""
        fake_image = base64.b64encode(b"\xff\xd8\xff\xe0test").decode()

        mock_request.return_value = {
            "status": 200,
            "data": {
                "choices": [
                    {
                        "message": {
                            "images": [
                                {
                                    "image_url": {
                                        "url": f"data:image/jpeg;base64,{fake_image}"
                                    }
                                }
                            ]
                        }
                    }
                ]
            },
            "error": None,
        }

        result = generate_image(prompt="Test prompt", output_dir=tmp_path)

        assert result["success"] is True
        assert Path(result["path"]).exists()

    @patch("gen_image.make_request")
    def test_generate_no_images_in_response(self, mock_request, tmp_path):
        """Should return error when no images in response."""
        mock_request.return_value = {
            "status": 200,
            "data": {
                "choices": [
                    {"message": {"content": "Sorry, I cannot generate images."}}
                ]
            },
            "error": None,
        }

        result = generate_image(prompt="Test prompt", output_dir=tmp_path)

        assert result["success"] is False
        assert "No images" in result["error"]

    @patch("gen_image.make_request")
    def test_generate_request_failed(self, mock_request, tmp_path):
        """Should return error when request fails."""
        mock_request.return_value = {
            "status": 500,
            "data": None,
            "error": "HTTP 500: Internal Server Error",
        }

        result = generate_image(prompt="Test prompt", output_dir=tmp_path)

        assert result["success"] is False
        assert "Request failed" in result["error"]


if __name__ == "__main__":
    import pytest

    pytest.main([__file__, "-v"])
