"""Integration tests for the main flow with mocked canopy."""
import json
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

from main import _generate_figure
from utils.json_builder import build_and_save_config, build_config


class TestGenerateFigureIntegration:
    """Integration tests for _generate_figure with mocked canopy."""

    def test_generate_figure_success(self):
        """Full flow: build config, write JSON, run_json (mocked) returns output paths."""
        mock_canopy = MagicMock()
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch.dict("sys.modules", {"canopy": mock_canopy}):
                result, error = _generate_figure(
                    temp_dir=tmpdir,
                    fields=["/data/file1.nc"],
                    figure="time_series",
                    state={"title": "Test Figure"},
                )

                assert error is None
                assert result is not None
                output_path, json_path = result
                assert Path(json_path).exists()
                assert output_path.endswith("figure.png")
                assert json_path.endswith("config.json")

                mock_canopy.run_json.assert_called_once()
                call_args = mock_canopy.run_json.call_args[0][0]
                assert call_args == json_path

                # Verify JSON content
                with open(json_path) as f:
                    cfg = json.load(f)
                assert cfg["figure"] == "time_series"
                assert cfg["input_file"] == "/data/file1.nc"
                assert cfg["title"] == "Test Figure"

    def test_generate_figure_map_simple(self):
        """Map figure with layer produces correct config."""
        mock_canopy = MagicMock()
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch.dict("sys.modules", {"canopy": mock_canopy}):
                result, error = _generate_figure(
                    temp_dir=tmpdir,
                    fields=["/data/map.nc"],
                    figure="map_simple",
                    state={"layer": "temperature", "proj": "PlateCarree"},
                )

                assert error is None
                output_path, json_path = result
                with open(json_path) as f:
                    cfg = json.load(f)
                assert cfg["figure"] == "map_simple"
                assert cfg["layer"] == "temperature"
                assert cfg["proj"] == "PlateCarree"

    def test_generate_figure_map_diff_two_files(self):
        """Map diff with two files."""
        mock_canopy = MagicMock()
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch.dict("sys.modules", {"canopy": mock_canopy}):
                result, error = _generate_figure(
                    temp_dir=tmpdir,
                    fields=["/data/a.nc", "/data/b.nc"],
                    figure="map_diff",
                    state={"layer": "var", "percentage": True},
                )

                assert error is None
                output_path, json_path = result
                with open(json_path) as f:
                    cfg = json.load(f)
                assert cfg["figure"] == "map_diff"
                assert cfg["input_file"] == ["/data/a.nc", "/data/b.nc"]
                assert cfg["layer"] == "var"
                assert cfg["percentage"] is True

    def test_generate_figure_canopy_exception_returns_error(self):
        """When canopy.run_json raises, error message is returned."""
        mock_canopy = MagicMock()
        mock_canopy.run_json.side_effect = RuntimeError("Canopy failed")
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch.dict("sys.modules", {"canopy": mock_canopy}):

                result, error = _generate_figure(
                    temp_dir=tmpdir,
                    fields=["/data/file.nc"],
                    figure="time_series",
                    state={},
                )

                assert result is None
                assert error is not None
                assert "Canopy failed" in error or "error" in error.lower()

    def test_generate_figure_build_config_exception_returns_error(self):
        """When build_and_save_config raises, error is propagated."""
        mock_canopy = MagicMock()
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch.dict("sys.modules", {"canopy": mock_canopy}), patch(
                "main.build_and_save_config"
            ) as mock_build:
                mock_build.side_effect = ValueError("Invalid state")

                result, error = _generate_figure(
                    temp_dir=tmpdir,
                    fields=["/data/file.nc"],
                    figure="time_series",
                    state={},
                )

                assert result is None
                assert error is not None


class TestBuildAndSaveConfigIntegration:
    """Integration tests for build_and_save_config (used by _generate_figure)."""

    def test_config_matches_canopy_expectations(self):
        """Config structure matches what canopy.run_json expects."""
        with tempfile.TemporaryDirectory() as tmpdir:
            json_path, output_path = build_and_save_config(
                fields=["/input/file.nc"],
                figure="time_series",
                state={
                    "layers": "var1",
                    "yaxis_lim": "0, 100",
                    "title": "Integration Test",
                },
                temp_dir=tmpdir,
            )

            with open(json_path) as f:
                cfg = json.load(f)

            # Required keys for canopy
            assert "figure" in cfg
            assert "input_file" in cfg
            assert "output_file" in cfg
            assert cfg["output_file"] == output_path
            assert cfg["yaxis_lim"] == [0.0, 100.0]
