"""
Step 13 — Markdown in Description Fields
- test_markdown_hint_on_exercise_form: Hint text visible next to description label on exercise form
- test_markdown_hint_on_combo_form: Hint text visible next to description label on combo form
- test_markdown_hint_on_session_form: Hint text visible next to description label on session form
- test_markdown_rendered_in_exercise_detail: Bold, italic and list render as HTML in exercise detail
- test_markdown_rendered_in_combo_detail: Bold text renders as HTML in combo detail
- test_markdown_rendered_in_session_detail: Bold text renders as HTML in session detail
- test_description_absent_from_exercise_list: Description is not shown on exercise list cards
- test_description_absent_from_combo_list: Description is not shown on combo list cards
- test_description_absent_from_session_list: Description is not shown on session list cards
"""
from playwright.sync_api import Page, expect

HINT_TEXT = "Basic Markdown supported"


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 _clean_all(page: Page):
    """Remove all exercises, combos, and sessions via the repositories."""
    page.evaluate(
        """async () => {
            for (const e of await window.__repos.exercises.getAll())
                await window.__repos.exercises.delete(e.id);
            for (const c of await window.__repos.combos.getAll())
                await window.__repos.combos.delete(c.id);
            for (const s of await window.__repos.sessions.getAll())
                await window.__repos.sessions.delete(s.id);
        }"""
    )


# ---------------------------------------------------------------------------
# Hint tests
# ---------------------------------------------------------------------------

def test_markdown_hint_on_exercise_form(page: Page, app_url: str):
    """Hint 'Basic Markdown supported' appears next to the description label on the exercise form."""
    _wait_for_db(page, app_url)
    page.click('a[href="#/exercises"]')
    page.wait_for_timeout(500)
    page.click('[data-testid="exercise-new-btn"]')
    page.wait_for_selector('[data-testid="exercise-description"]')

    hint = page.locator('[data-testid="exercise-description"]').locator(
        'xpath=../label .field-hint'
    )
    # Locate via the form-group label
    hint = page.locator('label[for="exercise-description"] .field-hint')
    expect(hint).to_have_text(HINT_TEXT)


def test_markdown_hint_on_combo_form(page: Page, app_url: str):
    """Hint 'Basic Markdown supported' appears next to the description label on the combo form."""
    _wait_for_db(page, app_url)
    page.click('a[href="#/combos"]')
    page.wait_for_timeout(500)
    page.click('[data-testid="combo-new-btn"]')
    page.wait_for_selector('[data-testid="combo-description"]')

    hint = page.locator('label[for="combo-description"] .field-hint')
    expect(hint).to_have_text(HINT_TEXT)


def test_markdown_hint_on_session_form(page: Page, app_url: str):
    """Hint 'Basic Markdown supported' appears next to the description label on the session form."""
    _wait_for_db(page, app_url)
    page.click('a[href="#/sessions"]')
    page.wait_for_timeout(500)
    page.click('[data-testid="session-new-btn"]')
    page.wait_for_selector('[data-testid="session-description"]')

    hint = page.locator('label[for="session-description"] .field-hint')
    expect(hint).to_have_text(HINT_TEXT)


# ---------------------------------------------------------------------------
# Rendering tests
# ---------------------------------------------------------------------------

def test_markdown_rendered_in_exercise_detail(page: Page, app_url: str):
    """Bold, italic, and list items in a description render as HTML elements in the exercise detail view."""
    _wait_for_db(page, app_url)
    _clean_all(page)

    exercise_id = page.evaluate(
        """async () => {
            const uuid = await window.__repos.settings.get('user_uuid');
            return window.__repos.exercises.create({
                title: 'MD Exercise',
                description: '**bold** and *italic*\\n- item one',
                created_by: uuid,
            });
        }"""
    )

    page.goto(f"{app_url}/#/exercises/{exercise_id}")
    page.wait_for_selector('[data-testid="exercise-detail-description"]')

    desc = page.locator('[data-testid="exercise-detail-description"]')
    expect(desc.locator('strong')).to_have_text('bold')
    expect(desc.locator('em')).to_have_text('italic')
    expect(desc.locator('li').first).to_have_text('item one')

    _clean_all(page)


def test_markdown_rendered_in_combo_detail(page: Page, app_url: str):
    """Bold text in a combo description renders as a <strong> element in the detail view."""
    _wait_for_db(page, app_url)
    _clean_all(page)

    combo_id = page.evaluate(
        """async () => {
            const uuid = await window.__repos.settings.get('user_uuid');
            return window.__repos.combos.create({
                title: 'MD Combo',
                description: '**important**',
                type: 'NONE',
                exercises: [],
                timer_config: {},
                created_by: uuid,
            });
        }"""
    )

    page.goto(f"{app_url}/#/combos/{combo_id}")
    page.wait_for_selector('[data-testid="combo-detail-description"]')

    desc = page.locator('[data-testid="combo-detail-description"]')
    expect(desc.locator('strong')).to_have_text('important')

    _clean_all(page)


def test_markdown_rendered_in_session_detail(page: Page, app_url: str):
    """Bold text in a session description renders as a <strong> element in the detail view."""
    _wait_for_db(page, app_url)
    _clean_all(page)

    session_id = page.evaluate(
        """async () => {
            const uuid = await window.__repos.settings.get('user_uuid');
            return window.__repos.sessions.create({
                title: 'MD Session',
                description: '**focus**',
                items: [],
                created_by: uuid,
            });
        }"""
    )

    page.goto(f"{app_url}/#/sessions/{session_id}")
    page.wait_for_selector('[data-testid="session-detail-description"]')

    desc = page.locator('[data-testid="session-detail-description"]')
    expect(desc.locator('strong')).to_have_text('focus')

    _clean_all(page)


# ---------------------------------------------------------------------------
# List view — description must not appear
# ---------------------------------------------------------------------------

def test_description_absent_from_exercise_list(page: Page, app_url: str):
    """Exercise list cards do not display the description text."""
    _wait_for_db(page, app_url)
    _clean_all(page)

    page.evaluate(
        """async () => {
            const uuid = await window.__repos.settings.get('user_uuid');
            await window.__repos.exercises.create({
                title: 'No Desc Exercise',
                description: 'should not be visible in list',
                created_by: uuid,
            });
        }"""
    )

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

    expect(page.get_by_text('should not be visible in list')).not_to_be_visible()

    _clean_all(page)


def test_description_absent_from_combo_list(page: Page, app_url: str):
    """Combo list cards do not display the description text."""
    _wait_for_db(page, app_url)
    _clean_all(page)

    page.evaluate(
        """async () => {
            const uuid = await window.__repos.settings.get('user_uuid');
            await window.__repos.combos.create({
                title: 'No Desc Combo',
                description: 'combo desc not in list',
                type: 'NONE',
                exercises: [],
                timer_config: {},
                created_by: uuid,
            });
        }"""
    )

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

    expect(page.get_by_text('combo desc not in list')).not_to_be_visible()

    _clean_all(page)


def test_description_absent_from_session_list(page: Page, app_url: str):
    """Session list cards do not display the description text."""
    _wait_for_db(page, app_url)
    _clean_all(page)

    page.evaluate(
        """async () => {
            const uuid = await window.__repos.settings.get('user_uuid');
            await window.__repos.sessions.create({
                title: 'No Desc Session',
                description: 'session desc not in list',
                items: [],
                created_by: uuid,
            });
        }"""
    )

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

    expect(page.get_by_text('session desc not in list')).not_to_be_visible()

    _clean_all(page)
