"""What each source_adoption mode tells the build agent, per project framework.

A real run asked P2HS to "replace" a project with a prototype and (through its own wording) to serve the
prototype's pages verbatim; the agent copied HTML into public/ inside a Nuxt project. "migrate" -- the
mode that means "turn this into a real app in the project's framework" -- had no description at all
(the agent was told to infer it). Each mode now says what it means, and for a framework project a
conversion means components with an identical rendered result, not files served as they are."""

from __future__ import annotations

from types import SimpleNamespace
from unittest.mock import AsyncMock
from uuid import uuid4

import pytest
from src.domain.codegen.agent_facade import _adoption_line
from tests.test_agent_attachments import _build, _facade, _grant

FILES = [{"path": "index.html", "content": "<h1>Exact design</h1>"},
         {"path": "assets/css/styles.css", "content": "h1{color:#12588d}"}]


async def prompt_for(project_type, source_adoption):
    facade = _facade()
    project = SimpleNamespace(id=uuid4(), workspace_id=uuid4(), type=project_type, discovery_json=None) \
        if project_type else None
    facade.projects.get_by_id = AsyncMock(return_value=project)
    facade._snapshot_attachments = AsyncMock(return_value=None)  # no disk in a unit test
    await facade.start(_grant(), _build(attachments=FILES, source_adoption=source_adoption))
    return facade.service.create_run.await_args.kwargs["user_prompt"]


@pytest.mark.asyncio
@pytest.mark.parametrize("project_type,framework", [("nuxt_app", "Nuxt (Vue)"), ("react_app", "React")])
async def test_migrate_in_a_framework_project_means_a_real_conversion_not_static_files(project_type, framework):
    prompt = await prompt_for(project_type, "migrate")
    assert "Adoption mode not specified" not in prompt  # it used to fall through to this
    assert f"Convert this existing app into this project's own framework ({framework}" in prompt
    assert "RENDERED result is identical" in prompt
    assert "port the JavaScript behavior" in prompt
    assert "Do not satisfy this by copying the attached files in and serving them as static files" in prompt


@pytest.mark.asyncio
async def test_replace_in_a_framework_project_is_implemented_in_that_framework():
    prompt = await prompt_for("nuxt_app", "replace")
    assert "Replace the relevant existing surface with this." in prompt  # the existing wording stays
    assert "own framework (Nuxt (Vue)" in prompt and "identical rendered result" in prompt
    # an explicit request can still ask for static serving; that is what an html project is for
    assert "unless the request explicitly asks" in prompt and "static html project" in prompt


@pytest.mark.asyncio
async def test_a_static_html_project_is_not_told_to_convert_to_a_framework():
    replaced = await prompt_for("html", "replace")
    assert "Replace the relevant existing surface with this." in replaced
    assert "own framework" not in replaced
    migrated = await prompt_for("html", "migrate")
    assert "keeping the rendered result identical" in migrated and "own framework" not in migrated
    assert "static files" not in migrated  # nothing to forbid in a static project


@pytest.mark.asyncio
async def test_migrate_with_an_unknown_project_type_still_says_what_it_means():
    prompt = await prompt_for(None, "migrate")
    assert "Adoption mode not specified" not in prompt
    assert "keeping the rendered result identical" in prompt


@pytest.mark.asyncio
@pytest.mark.parametrize("mode,text", [
    ("add", "Add this alongside what already exists in the project."),
    ("merge", "Merge this into the existing project, reconciling with what's already there."),
    ("inject", "Inject this into the existing project at the place the request names"),
])
async def test_the_other_modes_keep_their_meaning_and_inject_now_has_one(mode, text):
    assert text in await prompt_for("nuxt_app", mode)


@pytest.mark.asyncio
async def test_no_mode_is_still_left_to_inference():
    assert "Adoption mode not specified" in await prompt_for("nuxt_app", None)


def test_the_line_is_built_from_the_mode_and_the_project_type_only():
    assert "Nuxt (Vue)" in _adoption_line("migrate", "nuxt_app")
    assert "React" in _adoption_line("migrate", "react_app")
    assert _adoption_line("add", "nuxt_app") == "Add this alongside what already exists in the project."
