"""
Step 6 — Collection Management & Home Page Tests
- test_collection_list_empty: Shows empty state when no collections exist
- test_create_collection_minimal: Create collection with only required field (label)
- test_create_collection_with_sessions: Create collection with sessions
- test_collection_appears_in_list: Created collection appears in the list
- test_collection_detail_view: Detail view shows all collection data
- test_edit_collection: Edit a collection and verify changes
- test_delete_collection: Delete a collection with confirmation
- test_delete_collection_cancel: Cancelling delete does not remove collection
- test_search_collections: Search filters collections by label
- test_search_no_results: Search with no matches shows empty message
- test_search_clear_button: Clear button empties the search field and restores the full list
- test_validation_label_required: Empty label shows validation error
- test_duplicate_label_rejected: Creating collection with duplicate label shows error
- test_reorder_sessions: Reorder sessions in collection
- test_remove_session: Remove a session from collection
- test_action_bar_buttons: New and Search buttons appear in action bar
- test_navigate_to_session_from_collection: Click session in collection detail navigates to session
- test_home_empty_state: Home shows empty state when no executions exist
- test_home_recent_sessions: Home shows last 4 executed sessions with dates
- test_home_session_counts: Home shows session counts for last 7 and 30 days
- test_home_history_section: History section groups execution logs by calendar day
- test_home_history_date_filter: History section hides logs outside the active date range
- test_home_play_button_visible: Play button is visible on recent session cards
- test_home_export_html_button: HTML export button visible when data exists, absent otherwise
"""
from playwright.sync_api import Page, expect
from datetime import datetime, timedelta


def _wait_for_db(page: Page, app_url: str):
    """Navigate and wait for the database to be ready."""
    page.goto(app_url)
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )


def _go_to_collections(page: Page, app_url: str):
    """Navigate to the collections list and wait for it to load."""
    _wait_for_db(page, app_url)
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)


def _go_to_home(page: Page, app_url: str):
    """Navigate to the home page and wait for it to load."""
    _wait_for_db(page, app_url)
    page.click('a[href="#/home"]')
    page.wait_for_timeout(500)


def _clean_collections(page: Page):
    """Remove all collections via the repository."""
    page.evaluate(
        """async () => {
            const collections = await window.__repos.collections.getAll();
            for (const c of collections) {
                await window.__repos.collections.delete(c.id);
            }
        }"""
    )


def _clean_sessions(page: Page):
    """Remove all sessions via the repository."""
    page.evaluate(
        """async () => {
            const sessions = await window.__repos.sessions.getAll();
            for (const s of sessions) {
                await window.__repos.sessions.delete(s.id);
            }
        }"""
    )


def _clean_execution_logs(page: Page):
    """Remove all execution logs via the repository."""
    page.evaluate(
        """async () => {
            const logs = await window.__repos.executionLogs.getAll();
            for (const log of logs) {
                await window.__repos.executionLogs.delete(log.id);
            }
        }"""
    )


def _create_session_via_repo(page: Page, title):
    """Create a session via the repository and return its ID."""
    return page.evaluate(
        """async (title) => {
            const uuid = await window.__repos.settings.get('user_uuid');
            return window.__repos.sessions.create({
                title: title, description: '', created_by: uuid
            });
        }""",
        title,
    )


def test_collection_list_empty(page: Page, app_url: str):
    """Empty state is shown when no collections exist."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)
    expect(page.locator('[data-testid="collection-empty"]')).to_be_visible()


def test_create_collection_minimal(page: Page, app_url: str):
    """Create a collection with only the required label field."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')

    page.fill('[data-testid="collection-label"]', "My First Collection")
    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    expect(page.locator('[data-testid="collection-detail-title"]')).to_have_text(
        "My First Collection"
    )

    _clean_collections(page)


def test_create_collection_with_sessions(page: Page, app_url: str):
    """Create a collection with sessions."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    _clean_sessions(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    # Create sessions
    session1_id = _create_session_via_repo(page, "Morning Workout")
    session2_id = _create_session_via_repo(page, "Evening Stretch")

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    # Create collection
    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')

    page.fill('[data-testid="collection-label"]', "Weekly Plan")

    # Add sessions
    page.select_option('[data-testid="collection-session-select"]', session1_id)
    page.click('[data-testid="collection-session-add"]')

    page.select_option('[data-testid="collection-session-select"]', session2_id)
    page.click('[data-testid="collection-session-add"]')

    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    expect(page.locator('[data-testid="collection-detail-title"]')).to_have_text("Weekly Plan")
    expect(page.locator('[data-testid="collection-detail-session-0"]')).to_contain_text(
        "Morning Workout"
    )
    expect(page.locator('[data-testid="collection-detail-session-1"]')).to_contain_text(
        "Evening Stretch"
    )

    _clean_collections(page)
    _clean_sessions(page)


def test_collection_appears_in_list(page: Page, app_url: str):
    """Created collection appears in the list view."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')
    page.fill('[data-testid="collection-label"]', "Test Collection")
    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    page.click('[data-testid="collection-back-btn"]')
    page.wait_for_timeout(500)

    expect(page.locator('[data-testid="collection-card-title"]')).to_have_text("Test Collection")

    _clean_collections(page)


def test_collection_detail_view(page: Page, app_url: str):
    """Detail view shows all collection data correctly."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    _clean_sessions(page)

    session_id = _create_session_via_repo(page, "HIIT Session")

    # Create collection via repo
    collection_id = page.evaluate(
        """async ({ sessionId }) => {
            const uuid = await window.__repos.settings.get('user_uuid');
            const id = await window.__repos.collections.create({
                label: 'Training Week', created_by: uuid
            });
            await window.__repos.collections.setSessions(id, [sessionId]);
            return id;
        }""",
        {"sessionId": session_id},
    )

    page.goto(f"{app_url}/#/collections/{collection_id}")
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    expect(page.locator('[data-testid="collection-detail-title"]')).to_have_text("Training Week")
    expect(page.locator('[data-testid="collection-detail-session-0"]')).to_contain_text(
        "HIIT Session"
    )

    _clean_collections(page)
    _clean_sessions(page)


def test_edit_collection(page: Page, app_url: str):
    """Edit a collection and verify changes are persisted."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')
    page.fill('[data-testid="collection-label"]', "Original Label")
    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    page.click('[data-testid="collection-edit-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')

    page.fill('[data-testid="collection-label"]', "Updated Label")

    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    expect(page.locator('[data-testid="collection-detail-title"]')).to_have_text("Updated Label")

    _clean_collections(page)


def test_delete_collection(page: Page, app_url: str):
    """Delete a collection with confirmation dialog."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')
    page.fill('[data-testid="collection-label"]', "To Delete")
    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    page.on("dialog", lambda dialog: dialog.accept())
    page.click('[data-testid="collection-delete-btn"]')
    page.wait_for_timeout(500)

    expect(page.locator('[data-testid="collection-empty"]')).to_be_visible()


def test_delete_collection_cancel(page: Page, app_url: str):
    """Cancelling the delete dialog does not remove the collection."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')
    page.fill('[data-testid="collection-label"]', "Keep Me")
    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    page.on("dialog", lambda dialog: dialog.dismiss())
    page.click('[data-testid="collection-delete-btn"]')
    page.wait_for_timeout(500)

    expect(page.locator('[data-testid="collection-detail-title"]')).to_have_text("Keep Me")

    _clean_collections(page)


def test_search_collections(page: Page, app_url: str):
    """Search filters collections by label."""
    _go_to_collections(page, app_url)
    _clean_collections(page)

    page.evaluate(
        """async () => {
            const uuid = await window.__repos.settings.get('user_uuid');
            await window.__repos.collections.create({
                label: 'Upper Body Week', created_by: uuid
            });
            await window.__repos.collections.create({
                label: 'Lower Body Week', created_by: uuid
            });
            await window.__repos.collections.create({
                label: 'Full Body Week', created_by: uuid
            });
        }"""
    )

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    expect(page.locator('[data-testid="collection-card-title"]')).to_have_count(3)

    page.click('[data-testid="collection-search-toggle"]')
    page.wait_for_selector('[data-testid="collection-search-input"]')

    page.fill('[data-testid="collection-search-input"]', "Upper")
    page.wait_for_timeout(500)

    expect(page.locator('[data-testid="collection-card-title"]')).to_have_count(1)
    expect(page.locator('[data-testid="collection-card-title"]')).to_have_text("Upper Body Week")

    _clean_collections(page)


def test_search_no_results(page: Page, app_url: str):
    """Search with no matches shows no-results message."""
    _go_to_collections(page, app_url)
    _clean_collections(page)

    page.evaluate(
        """async () => {
            const uuid = await window.__repos.settings.get('user_uuid');
            await window.__repos.collections.create({
                label: 'Upper Body Week', created_by: uuid
            });
        }"""
    )

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-search-toggle"]')
    page.fill('[data-testid="collection-search-input"]', "zzzznotfound")
    page.wait_for_timeout(500)

    expect(page.locator('[data-testid="collection-no-results"]')).to_be_visible()

    _clean_collections(page)


def test_search_clear_button(page: Page, app_url: str):
    """Clear button empties the search field and restores the full list."""
    _go_to_collections(page, app_url)
    _clean_collections(page)

    page.evaluate(
        """async () => {
            const uuid = await window.__repos.settings.get('user_uuid');
            await window.__repos.collections.create({
                label: 'Upper Body Week', created_by: uuid
            });
            await window.__repos.collections.create({
                label: 'Lower Body Week', created_by: uuid
            });
        }"""
    )

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-search-toggle"]')

    expect(page.locator('[data-testid="collection-search-clear"]')).not_to_be_visible()

    page.fill('[data-testid="collection-search-input"]', "Upper")
    page.wait_for_timeout(500)
    expect(page.locator('[data-testid="collection-card-title"]')).to_have_count(1)

    page.click('[data-testid="collection-search-clear"]')
    expect(page.locator('[data-testid="collection-search-input"]')).to_have_value("")
    page.wait_for_timeout(500)
    expect(page.locator('[data-testid="collection-card-title"]')).to_have_count(2)

    expect(page.locator('[data-testid="collection-search-input"]')).to_be_focused()

    _clean_collections(page)


def test_validation_label_required(page: Page, app_url: str):
    """Empty label shows validation error and prevents save."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')

    page.click('[data-testid="collection-save"]')

    expect(page.locator('[data-testid="collection-label-error"]')).to_be_visible()
    expect(page.locator('[data-testid="collection-label"]')).to_be_visible()


def test_duplicate_label_rejected(page: Page, app_url: str):
    """Creating a collection with a duplicate label shows an error."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')
    page.fill('[data-testid="collection-label"]', "Unique Collection")
    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    page.click('[data-testid="collection-back-btn"]')
    page.wait_for_timeout(500)

    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')
    page.fill('[data-testid="collection-label"]', "Unique Collection")
    page.click('[data-testid="collection-save"]')
    page.wait_for_timeout(500)

    label_error_visible = page.locator('[data-testid="collection-label-error"]').is_visible()
    save_error_visible = page.locator('[data-testid="collection-save-error"]').is_visible()
    assert label_error_visible or save_error_visible, "Expected duplicate label error"

    _clean_collections(page)


def test_reorder_sessions(page: Page, app_url: str):
    """Reorder sessions in a collection."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    _clean_sessions(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    s1_id = _create_session_via_repo(page, "Session A")
    s2_id = _create_session_via_repo(page, "Session B")
    s3_id = _create_session_via_repo(page, "Session C")

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    # Create collection with 3 sessions
    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')
    page.fill('[data-testid="collection-label"]', "Reorder Test")

    for s_id in [s1_id, s2_id, s3_id]:
        page.select_option('[data-testid="collection-session-select"]', s_id)
        page.click('[data-testid="collection-session-add"]')

    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    # Go to edit
    page.click('[data-testid="collection-edit-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')

    # Move Session B (index 1) up
    page.click('[data-testid="collection-session-move-up-1"]')

    # Save
    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    # Verify order: Session B, Session A, Session C
    expect(page.locator('[data-testid="collection-detail-session-0"]')).to_contain_text("Session B")
    expect(page.locator('[data-testid="collection-detail-session-1"]')).to_contain_text("Session A")
    expect(page.locator('[data-testid="collection-detail-session-2"]')).to_contain_text("Session C")

    _clean_collections(page)
    _clean_sessions(page)


def test_remove_session(page: Page, app_url: str):
    """Remove a session from a collection."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    _clean_sessions(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    s1_id = _create_session_via_repo(page, "Session A")
    s2_id = _create_session_via_repo(page, "Session B")

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    # Create collection with 2 sessions
    page.click('[data-testid="collection-new-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')
    page.fill('[data-testid="collection-label"]', "Remove Test")

    for s_id in [s1_id, s2_id]:
        page.select_option('[data-testid="collection-session-select"]', s_id)
        page.click('[data-testid="collection-session-add"]')

    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    # Go to edit
    page.click('[data-testid="collection-edit-btn"]')
    page.wait_for_selector('[data-testid="collection-label"]')

    # Remove first session
    page.click('[data-testid="collection-session-remove-0"]')

    page.click('[data-testid="collection-save"]')
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    # Only Session B should remain
    expect(page.locator('[data-testid="collection-detail-session-0"]')).to_contain_text("Session B")

    _clean_collections(page)
    _clean_sessions(page)


def test_action_bar_buttons(page: Page, app_url: str):
    """New and Search buttons are visible in the action bar on the collection list."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/collections"]')
    page.wait_for_timeout(500)

    expect(page.locator('[data-testid="collection-new-btn"]')).to_be_visible()
    expect(page.locator('[data-testid="collection-search-toggle"]')).to_be_visible()


def test_navigate_to_session_from_collection(page: Page, app_url: str):
    """Clicking a session in collection detail navigates to session detail."""
    _go_to_collections(page, app_url)
    _clean_collections(page)
    _clean_sessions(page)

    session_id = _create_session_via_repo(page, "Target Session")

    collection_id = page.evaluate(
        """async ({ sessionId }) => {
            const uuid = await window.__repos.settings.get('user_uuid');
            const id = await window.__repos.collections.create({
                label: 'Navigation Test', created_by: uuid
            });
            await window.__repos.collections.setSessions(id, [sessionId]);
            return id;
        }""",
        {"sessionId": session_id},
    )

    page.goto(f"{app_url}/#/collections/{collection_id}")
    page.wait_for_selector('[data-testid="collection-detail-title"]', timeout=5000)

    page.click('[data-testid="collection-detail-session-link-0"]')
    page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)

    expect(page.locator('[data-testid="session-detail-title"]')).to_have_text("Target Session")

    _clean_collections(page)
    _clean_sessions(page)


def test_home_empty_state(page: Page, app_url: str):
    """Home shows empty state when no executions exist."""
    _go_to_home(page, app_url)
    _clean_execution_logs(page)
    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/home"]')
    page.wait_for_timeout(500)

    expect(page.locator('[data-testid="home-empty"]')).to_be_visible()


def test_home_recent_sessions(page: Page, app_url: str):
    """Home shows last 4 executed sessions with inline exercise summaries."""
    _go_to_home(page, app_url)
    _clean_execution_logs(page)
    _clean_sessions(page)

    # Create sessions
    session1_id = _create_session_via_repo(page, "Session One")
    session2_id = _create_session_via_repo(page, "Session Two")
    session3_id = _create_session_via_repo(page, "Session Three")
    session4_id = _create_session_via_repo(page, "Session Four")

    # Create execution logs with different dates
    page.evaluate(
        """async ({ s1, s2, s3, s4 }) => {
            const now = new Date();
            const logs = [
                { session_id: s1, started_at: new Date(now - 4 * 86400000).toISOString(), finished_at: new Date(now - 4 * 86400000 + 3600000).toISOString() },
                { session_id: s2, started_at: new Date(now - 3 * 86400000).toISOString(), finished_at: new Date(now - 3 * 86400000 + 3600000).toISOString() },
                { session_id: s3, started_at: new Date(now - 2 * 86400000).toISOString(), finished_at: new Date(now - 2 * 86400000 + 3600000).toISOString() },
                { session_id: s4, started_at: new Date(now - 1 * 86400000).toISOString(), finished_at: new Date(now - 1 * 86400000 + 3600000).toISOString() },
            ];
            for (const log of logs) {
                await window.__repos.executionLogs.create(log);
            }
        }""",
        {"s1": session1_id, "s2": session2_id, "s3": session3_id, "s4": session4_id},
    )

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/home"]')
    page.wait_for_timeout(500)

    # Should show the 4 most recent (Session Four, Three, Two, One)
    expect(page.locator('[data-testid="home-recent-session-title"]')).to_have_count(4)

    # Most recent first
    expect(page.locator('[data-testid="home-recent-session-title"]').first).to_have_text(
        "Session Four"
    )

    _clean_execution_logs(page)
    _clean_sessions(page)


def test_home_session_counts(page: Page, app_url: str):
    """Home shows session counts for last 7 and 30 days."""
    _go_to_home(page, app_url)
    _clean_execution_logs(page)
    _clean_sessions(page)

    session_id = _create_session_via_repo(page, "Count Session")

    # Create 2 logs within 7 days, 3 more within 30 days
    page.evaluate(
        """async ({ sessionId }) => {
            const now = new Date();
            const logs = [
                { session_id: sessionId, started_at: new Date(now - 1 * 86400000).toISOString(), finished_at: new Date(now - 1 * 86400000 + 3600000).toISOString() },
                { session_id: sessionId, started_at: new Date(now - 3 * 86400000).toISOString(), finished_at: new Date(now - 3 * 86400000 + 3600000).toISOString() },
                { session_id: sessionId, started_at: new Date(now - 10 * 86400000).toISOString(), finished_at: new Date(now - 10 * 86400000 + 3600000).toISOString() },
                { session_id: sessionId, started_at: new Date(now - 15 * 86400000).toISOString(), finished_at: new Date(now - 15 * 86400000 + 3600000).toISOString() },
                { session_id: sessionId, started_at: new Date(now - 25 * 86400000).toISOString(), finished_at: new Date(now - 25 * 86400000 + 3600000).toISOString() },
            ];
            for (const log of logs) {
                await window.__repos.executionLogs.create(log);
            }
        }""",
        {"sessionId": session_id},
    )

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/home"]')
    page.wait_for_timeout(500)

    # 2 within 7 days
    expect(page.locator('[data-testid="home-stat-7days"] .stat-value')).to_have_text("2")
    # 5 within 30 days
    expect(page.locator('[data-testid="home-stat-30days"] .stat-value')).to_have_text("5")

    _clean_execution_logs(page)
    _clean_sessions(page)


def test_home_history_section(page: Page, app_url: str):
    """History section groups execution logs by calendar day."""
    _go_to_home(page, app_url)
    _clean_execution_logs(page)
    _clean_sessions(page)

    session_id = _create_session_via_repo(page, "History Session")

    # Two logs on two different days (today and yesterday)
    page.evaluate(
        """async ({ sessionId }) => {
            const now = new Date();
            const yesterday = new Date(now - 86400000);
            const logs = [
                { session_id: sessionId, started_at: now.toISOString(), finished_at: new Date(now.getTime() + 3600000).toISOString() },
                { session_id: sessionId, started_at: yesterday.toISOString(), finished_at: new Date(yesterday.getTime() + 3600000).toISOString() },
            ];
            for (const log of logs) {
                await window.__repos.executionLogs.create(log);
            }
        }""",
        {"sessionId": session_id},
    )

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/home"]')
    page.wait_for_timeout(500)

    # History section must show 2 day groups (the .history-day-label elements)
    expect(page.locator(".history-day-label")).to_have_count(2)

    # Both logs are visible as history cards
    history_cards = page.locator('[data-testid^="home-history-session-"]')
    expect(history_cards).to_have_count(2)

    _clean_execution_logs(page)
    _clean_sessions(page)


def test_home_history_date_filter(page: Page, app_url: str):
    """History section hides execution logs that fall outside the active date range."""
    _go_to_home(page, app_url)
    _clean_execution_logs(page)
    _clean_sessions(page)

    session_id = _create_session_via_repo(page, "Filter Session")

    # One log 5 days ago (inside default 30-day window) and one 40 days ago (outside)
    page.evaluate(
        """async ({ sessionId }) => {
            const now = new Date();
            const logs = [
                {
                    session_id: sessionId,
                    started_at: new Date(now - 5 * 86400000).toISOString(),
                    finished_at: new Date(now - 5 * 86400000 + 3600000).toISOString()
                },
                {
                    session_id: sessionId,
                    started_at: new Date(now - 40 * 86400000).toISOString(),
                    finished_at: new Date(now - 40 * 86400000 + 3600000).toISOString()
                },
            ];
            for (const log of logs) {
                await window.__repos.executionLogs.create(log);
            }
        }""",
        {"sessionId": session_id},
    )

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/home"]')
    page.wait_for_timeout(500)

    # Default filter is last 30 days: only the 5-day-ago log shows in history
    history_cards = page.locator('[data-testid^="home-history-session-"]')
    expect(history_cards).to_have_count(1)

    _clean_execution_logs(page)
    _clean_sessions(page)


def test_home_play_button_visible(page: Page, app_url: str):
    """Play button is visible on each recent session card."""
    _go_to_home(page, app_url)
    _clean_execution_logs(page)
    _clean_sessions(page)

    session_id = _create_session_via_repo(page, "Play Button Session")

    page.evaluate(
        """async ({ sessionId }) => {
            const now = new Date();
            await window.__repos.executionLogs.create({
                session_id: sessionId,
                started_at: now.toISOString(),
                finished_at: new Date(now.getTime() + 3600000).toISOString(),
            });
        }""",
        {"sessionId": session_id},
    )

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/home"]')
    page.wait_for_timeout(500)

    play_btn = page.locator(f'[data-testid="home-recent-session-play-{session_id}"]')
    expect(play_btn).to_be_visible()

    _clean_execution_logs(page)
    _clean_sessions(page)


def test_home_export_html_button(page: Page, app_url: str):
    """HTML export button is visible when execution logs exist and absent on empty state."""
    _go_to_home(page, app_url)
    _clean_execution_logs(page)
    _clean_sessions(page)

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/home"]')
    page.wait_for_timeout(500)

    # No data: export button must not be rendered
    expect(page.locator('[data-testid="home-export-html-btn"]')).to_have_count(0)

    # Create a session and an execution log
    session_id = _create_session_via_repo(page, "Export Session")
    page.evaluate(
        """async ({ sessionId }) => {
            const now = new Date();
            await window.__repos.executionLogs.create({
                session_id: sessionId,
                started_at: now.toISOString(),
                finished_at: new Date(now.getTime() + 1800000).toISOString(),
            });
        }""",
        {"sessionId": session_id},
    )

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )
    page.click('a[href="#/home"]')
    page.wait_for_timeout(500)

    # With data: export button must be visible
    expect(page.locator('[data-testid="home-export-html-btn"]')).to_be_visible()

    _clean_execution_logs(page)
    _clean_sessions(page)
