"""Tests for server.py Flask service."""
import json
import pathlib
import sys
from unittest.mock import patch

import pytest

sys.path.insert(0, str(pathlib.Path(__file__).parents[1]))

# Import the Flask app — will fail until server.py is created
from server import create_app

FIXTURES = pathlib.Path(__file__).parents[1] / "fixtures" / "brief_prada2.json"


@pytest.fixture
def brief():
    data = json.loads(FIXTURES.read_text(encoding="utf-8"))
    # Phase 2 fields (ISO date/time, required by fill_template pipeline)
    data["event_date"] = "2026-04-30"
    data["event_time"] = "20:00"
    return data


@pytest.fixture
def app():
    app = create_app({"TESTING": True, "OUTPUT_BASE_DIR": "/tmp/test_output"})
    return app


@pytest.fixture
def client(app):
    return app.test_client()


@pytest.fixture
def valid_payload(brief):
    return {
        "brief": brief,
        "selected_title_fr": "Laissez-vous emporter dans l'univers de la mode",
        "selected_title_nl": "Laat je meeslepen in de modewereld",
        "background_type": "image",
        "background_color": "#000000",
        "background_image_path": "/absolute/path/to/background.png",
        "campaign_slug": "prada2",
    }


class TestGenerateEndpointSuccess:
    """POST /generate with valid payload returns 200 with file paths."""

    def test_returns_200(self, client, valid_payload):
        with patch("server.compose_hero"), patch("server.fill_template", return_value="<html/>"), \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            resp = client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        assert resp.status_code == 200

    def test_response_contains_hero_fr_key(self, client, valid_payload):
        with patch("server.compose_hero"), patch("server.fill_template", return_value="<html/>"), \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            resp = client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        data = json.loads(resp.data)
        assert "hero_fr" in data

    def test_response_contains_hero_nl_key(self, client, valid_payload):
        with patch("server.compose_hero"), patch("server.fill_template", return_value="<html/>"), \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            resp = client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        data = json.loads(resp.data)
        assert "hero_nl" in data

    def test_response_contains_email_fr_key(self, client, valid_payload):
        with patch("server.compose_hero"), patch("server.fill_template", return_value="<html/>"), \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            resp = client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        data = json.loads(resp.data)
        assert "email_fr" in data

    def test_response_contains_email_nl_key(self, client, valid_payload):
        with patch("server.compose_hero"), patch("server.fill_template", return_value="<html/>"), \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            resp = client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        data = json.loads(resp.data)
        assert "email_nl" in data

    def test_paths_contain_campaign_slug(self, client, valid_payload):
        with patch("server.compose_hero"), patch("server.fill_template", return_value="<html/>"), \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            resp = client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        data = json.loads(resp.data)
        assert "prada2" in data["hero_fr"]
        assert "prada2" in data["hero_nl"]

    def test_compose_hero_called_twice(self, client, valid_payload):
        with patch("server.compose_hero") as mock_compose, \
             patch("server.fill_template", return_value="<html/>"), \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        assert mock_compose.call_count == 2

    def test_fill_template_called_twice(self, client, valid_payload):
        with patch("server.compose_hero"), \
             patch("server.fill_template", return_value="<html/>") as mock_fill, \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        assert mock_fill.call_count == 2

    def test_hero_title_injected_into_brief_fr(self, client, valid_payload):
        """The selected_title_fr must become brief["fr"]["hero_title"] before compose_hero."""
        calls = []
        def capture_compose(brief, *, lang, output_path):
            calls.append((lang, brief[lang]["hero_title"]))

        with patch("server.compose_hero", side_effect=capture_compose), \
             patch("server.fill_template", return_value="<html/>"), \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        fr_call = next(c for c in calls if c[0] == "fr")
        assert fr_call[1] == valid_payload["selected_title_fr"]

    def test_hero_title_injected_into_brief_nl(self, client, valid_payload):
        calls = []
        def capture_compose(brief, *, lang, output_path):
            calls.append((lang, brief[lang]["hero_title"]))

        with patch("server.compose_hero", side_effect=capture_compose), \
             patch("server.fill_template", return_value="<html/>"), \
             patch("pathlib.Path.mkdir"), patch("pathlib.Path.write_text"):
            client.post(
                "/generate",
                data=json.dumps(valid_payload),
                content_type="application/json",
            )
        nl_call = next(c for c in calls if c[0] == "nl")
        assert nl_call[1] == valid_payload["selected_title_nl"]


class TestGenerateEndpointValidation:
    """POST /generate with missing required fields returns 400."""

    def test_missing_brief_returns_400(self, client, valid_payload):
        del valid_payload["brief"]
        resp = client.post(
            "/generate",
            data=json.dumps(valid_payload),
            content_type="application/json",
        )
        assert resp.status_code == 400

    def test_missing_selected_title_fr_returns_400(self, client, valid_payload):
        del valid_payload["selected_title_fr"]
        resp = client.post(
            "/generate",
            data=json.dumps(valid_payload),
            content_type="application/json",
        )
        assert resp.status_code == 400

    def test_missing_selected_title_nl_returns_400(self, client, valid_payload):
        del valid_payload["selected_title_nl"]
        resp = client.post(
            "/generate",
            data=json.dumps(valid_payload),
            content_type="application/json",
        )
        assert resp.status_code == 400

    def test_missing_campaign_slug_returns_400(self, client, valid_payload):
        del valid_payload["campaign_slug"]
        resp = client.post(
            "/generate",
            data=json.dumps(valid_payload),
            content_type="application/json",
        )
        assert resp.status_code == 400

    def test_missing_background_type_returns_400(self, client, valid_payload):
        del valid_payload["background_type"]
        resp = client.post(
            "/generate",
            data=json.dumps(valid_payload),
            content_type="application/json",
        )
        assert resp.status_code == 400

    def test_error_response_contains_error_key(self, client, valid_payload):
        del valid_payload["brief"]
        resp = client.post(
            "/generate",
            data=json.dumps(valid_payload),
            content_type="application/json",
        )
        data = json.loads(resp.data)
        assert "error" in data

    def test_non_json_request_returns_400(self, client):
        resp = client.post("/generate", data="not json", content_type="text/plain")
        assert resp.status_code == 400


class TestHealthEndpoint:
    def test_health_returns_200(self, client):
        resp = client.get("/health")
        assert resp.status_code == 200

    def test_health_returns_ok(self, client):
        resp = client.get("/health")
        data = json.loads(resp.data)
        assert data.get("status") == "ok"
