"""Integration tests for rx.memo components."""

from collections.abc import Generator

import pytest
from selenium.webdriver.common.by import By

from reflex.testing import AppHarness


def MemoApp():
    """Reflex app with memo components."""
    import reflex as rx

    class FooComponent(rx.Fragment):
        def add_custom_code(self) -> list[str]:
            return [
                "const foo = 'bar'",
            ]

    @rx.memo
    def foo_component(t: str):
        return FooComponent.create(t, rx.Var("foo"))

    @rx.memo
    def foo_component2(t: str):
        return FooComponent.create(t, rx.Var("foo"))

    class MemoState(rx.State):
        last_value: str = ""

        @rx.event
        def set_last_value(self, value: str):
            self.last_value = value

    @rx.memo
    def my_memoed_component(
        some_value: str,
        event: rx.EventHandler[rx.event.passthrough_event_spec(str)],
    ) -> rx.Component:
        return rx.vstack(
            rx.button(some_value, id="memo-button", on_click=event(some_value)),
            rx.input(id="memo-input", on_change=event),
        )

    def index() -> rx.Component:
        return rx.vstack(
            rx.vstack(
                foo_component(t="foo"), foo_component2(t="bar"), id="memo-custom-code"
            ),
            rx.text(MemoState.last_value, id="memo-last-value"),
            my_memoed_component(
                some_value="memod_some_value", event=MemoState.set_last_value
            ),
        )

    app = rx.App()
    app.add_page(index)


@pytest.fixture()
def memo_app(tmp_path) -> Generator[AppHarness, None, None]:
    """Start MemoApp app at tmp_path via AppHarness.

    Args:
        tmp_path: pytest tmp_path fixture

    Yields:
        running AppHarness instance
    """
    with AppHarness.create(
        root=tmp_path,
        app_source=MemoApp,
    ) as harness:
        yield harness


@pytest.mark.asyncio
async def test_memo_app(memo_app: AppHarness):
    """Render various memo'd components and assert on the output.

    Args:
        memo_app: harness for MemoApp app
    """
    assert memo_app.app_instance is not None, "app is not running"
    driver = memo_app.frontend()

    # check that the output matches
    memo_custom_code_stack = driver.find_element(By.ID, "memo-custom-code")
    assert (
        memo_app.poll_for_content(memo_custom_code_stack, exp_not_equal="")
        == "foobarbarbar"
    )
    assert memo_custom_code_stack.text == "foobarbarbar"

    # click the button to trigger partial event application
    button = driver.find_element(By.ID, "memo-button")
    button.click()
    last_value = driver.find_element(By.ID, "memo-last-value")
    assert memo_app.poll_for_content(last_value, exp_not_equal="") == "memod_some_value"

    # enter text to trigger passed argument to event handler
    textbox = driver.find_element(By.ID, "memo-input")
    textbox.send_keys("new_value")
    assert memo_app._poll_for(
        lambda: memo_app.poll_for_content(last_value) == "new_value"
    )
