"""Tests for web/utils/vite_helper.py."""

import json
from unittest.mock import Mock, patch, mock_open


class TestViteHelperInit:
    """Tests for ViteHelper initialization."""

    def test_init_without_app(self):
        """Test initialization without Flask app."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        assert helper.app is None
        assert helper.manifest is None
        assert helper.is_dev is False

    def test_init_with_app_calls_init_app(self):
        """Test that initialization with app calls init_app."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        mock_app = Mock()
        mock_app.debug = False
        mock_app.config = {}
        mock_app.jinja_env = Mock()
        mock_app.jinja_env.globals = {}

        with patch.object(ViteHelper, "_load_manifest"):
            helper = ViteHelper(app=mock_app)
            assert helper.app is mock_app


class TestViteHelperInitApp:
    """Tests for ViteHelper.init_app method."""

    def test_init_app_sets_app_attribute(self):
        """Test that init_app sets the app attribute."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        mock_app = Mock()
        mock_app.debug = False
        mock_app.config = {}
        mock_app.jinja_env = Mock()
        mock_app.jinja_env.globals = {}

        with patch.object(helper, "_load_manifest"):
            helper.init_app(mock_app)
            assert helper.app is mock_app

    def test_init_app_sets_dev_mode_from_debug(self):
        """Test that is_dev is set from app.debug."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        mock_app = Mock()
        mock_app.debug = True
        mock_app.config = {}
        mock_app.jinja_env = Mock()
        mock_app.jinja_env.globals = {}

        helper.init_app(mock_app)
        assert helper.is_dev is True

    def test_init_app_sets_dev_mode_from_config(self):
        """Test that is_dev can be set from VITE_DEV_MODE config."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        mock_app = Mock()
        mock_app.debug = False
        mock_app.config = {"VITE_DEV_MODE": True}
        mock_app.jinja_env = Mock()
        mock_app.jinja_env.globals = {}

        helper.init_app(mock_app)
        assert helper.is_dev is True

    def test_init_app_registers_vite_asset_global(self):
        """Test that vite_asset is registered as Jinja global."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        mock_app = Mock()
        mock_app.debug = True
        mock_app.config = {}
        mock_app.jinja_env = Mock()
        mock_app.jinja_env.globals = {}

        helper.init_app(mock_app)
        assert "vite_asset" in mock_app.jinja_env.globals
        assert mock_app.jinja_env.globals["vite_asset"] == helper.vite_asset

    def test_init_app_registers_vite_hmr_global(self):
        """Test that vite_hmr is registered as Jinja global."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        mock_app = Mock()
        mock_app.debug = True
        mock_app.config = {}
        mock_app.jinja_env = Mock()
        mock_app.jinja_env.globals = {}

        helper.init_app(mock_app)
        assert "vite_hmr" in mock_app.jinja_env.globals
        assert mock_app.jinja_env.globals["vite_hmr"] == helper.vite_hmr

    def test_init_app_loads_manifest_in_production(self):
        """Test that manifest is loaded in production mode."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        mock_app = Mock()
        mock_app.debug = False
        mock_app.config = {}
        mock_app.jinja_env = Mock()
        mock_app.jinja_env.globals = {}

        with patch.object(helper, "_load_manifest") as mock_load:
            helper.init_app(mock_app)
            mock_load.assert_called_once()

    def test_init_app_skips_manifest_in_dev(self):
        """Test that manifest loading is skipped in dev mode."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        mock_app = Mock()
        mock_app.debug = True
        mock_app.config = {}
        mock_app.jinja_env = Mock()
        mock_app.jinja_env.globals = {}

        with patch.object(helper, "_load_manifest") as mock_load:
            helper.init_app(mock_app)
            mock_load.assert_not_called()


class TestViteHelperLoadManifest:
    """Tests for ViteHelper._load_manifest method."""

    def test_load_manifest_reads_json_file(self):
        """Test that manifest JSON is loaded from file."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.app = Mock()
        helper.app.config = {"STATIC_DIR": "/app/static"}

        manifest_data = {"js/app.js": {"file": "assets/app-abc123.js"}}

        with patch("pathlib.Path.exists", return_value=True):
            with patch(
                "builtins.open", mock_open(read_data=json.dumps(manifest_data))
            ):
                helper._load_manifest()
                assert helper.manifest == manifest_data

    def test_load_manifest_uses_default_static_dir(self):
        """Test that default static directory is used when not configured."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.app = Mock()
        helper.app.config = {}

        with patch("pathlib.Path.exists", return_value=False):
            helper._load_manifest()
            assert helper.manifest == {}

    def test_load_manifest_handles_missing_file(self):
        """Test that missing manifest file results in empty dict."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.app = Mock()
        helper.app.config = {"STATIC_DIR": "/app/static"}

        with patch("pathlib.Path.exists", return_value=False):
            helper._load_manifest()
            assert helper.manifest == {}


class TestViteHelperViteHmr:
    """Tests for ViteHelper.vite_hmr method."""

    def test_vite_hmr_returns_script_in_dev_mode(self):
        """Test that HMR script is returned in development mode."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.is_dev = True

        result = helper.vite_hmr()
        assert "localhost:5173" in str(result)
        assert "@vite/client" in str(result)
        assert '<script type="module"' in str(result)

    def test_vite_hmr_returns_empty_in_production(self):
        """Test that empty string is returned in production mode."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.is_dev = False

        result = helper.vite_hmr()
        assert result == ""


class TestViteHelperViteAsset:
    """Tests for ViteHelper.vite_asset method."""

    def test_vite_asset_returns_dev_server_url_in_dev_mode(self):
        """Test that dev server URL is returned in development mode."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.is_dev = True

        result = helper.vite_asset("js/app.js")
        assert "localhost:5173" in str(result)
        assert "js/app.js" in str(result)
        assert '<script type="module"' in str(result)

    def test_vite_asset_uses_default_entry_point(self):
        """Test that default entry point is used when not specified."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.is_dev = True

        result = helper.vite_asset()
        assert "js/app.js" in str(result)

    def test_vite_asset_returns_manifest_path_in_production(self):
        """Test that manifest file path is returned in production."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.is_dev = False
        helper.manifest = {
            "js/app.js": {
                "file": "assets/app-abc123.js",
            }
        }

        result = helper.vite_asset("js/app.js")
        assert "/static/dist/assets/app-abc123.js" in str(result)
        assert '<script type="module"' in str(result)

    def test_vite_asset_includes_css_from_manifest(self):
        """Test that CSS files from manifest are included."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.is_dev = False
        helper.manifest = {
            "js/app.js": {
                "file": "assets/app-abc123.js",
                "css": ["assets/app-abc123.css", "assets/vendor-def456.css"],
            }
        }

        result = helper.vite_asset("js/app.js")
        assert "/static/dist/assets/app-abc123.css" in str(result)
        assert "/static/dist/assets/vendor-def456.css" in str(result)
        assert '<link rel="stylesheet"' in str(result)

    def test_vite_asset_returns_fallback_when_no_manifest(self):
        """Test that fallback is returned when manifest is empty."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.is_dev = False
        helper.manifest = {}

        result = helper.vite_asset("js/app.js")
        assert "Vite build not found" in str(result)

    def test_vite_asset_returns_fallback_for_missing_entry(self):
        """Test that fallback is returned for missing entry point."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        helper.is_dev = False
        helper.manifest = {"other/file.js": {"file": "assets/other.js"}}

        result = helper.vite_asset("js/missing.js")
        assert "Vite build not found" in str(result)


class TestViteHelperFallbackAssets:
    """Tests for ViteHelper._fallback_assets method."""

    def test_fallback_assets_returns_comment(self):
        """Test that fallback returns informative HTML comment."""
        from local_deep_research.web.utils.vite_helper import ViteHelper

        helper = ViteHelper()
        result = helper._fallback_assets()

        assert "Vite build not found" in str(result)
        assert "npm run build" in str(result)


class TestViteSingleton:
    """Tests for the singleton vite instance."""

    def test_singleton_instance_exists(self):
        """Test that singleton vite instance exists."""
        from local_deep_research.web.utils.vite_helper import vite

        assert vite is not None

    def test_singleton_is_vite_helper_instance(self):
        """Test that singleton is a ViteHelper instance."""
        from local_deep_research.web.utils.vite_helper import vite, ViteHelper

        assert isinstance(vite, ViteHelper)
