"""
Step 22 — Save Filename Prompt Tests

Green paths:
- test_dialog_prefilled_with_default_name: Dialog opens with stem prefilled and extension shown
- test_custom_filename_is_used: Editing the stem changes the downloaded file's name
- test_enter_confirms_with_default: Pressing Enter accepts the prefilled default name
- test_empty_stem_falls_back_to_default: Clearing the stem and saving falls back to the default name

Red paths:
- test_cancel_aborts_download: Cancelling the dialog produces no download
- test_close_button_aborts_download: Closing the dialog (X button) produces no download
- test_backup_cancel_does_not_update_last_backup_at: Cancelling a backup save leaves last_backup_at untouched
- test_migration_cancel_keeps_update_disabled: Cancelling the forced migration backup leaves Update disabled
"""

import re

from playwright.sync_api import Page, expect


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_exercises(page: Page, app_url: str):
    """Navigate to the exercises list and wait for it to load."""
    _wait_for_db(page, app_url)
    page.click('a[href="#/exercises"]')
    page.wait_for_timeout(500)


def _go_to_settings(page: Page, app_url: str):
    """Navigate to the settings page and wait for DB."""
    _wait_for_db(page, app_url)
    page.click('a[href="#/settings"]')
    page.wait_for_selector('[data-testid="settings-language"]')


def _set_db_version(page: Page, version: int):
    """Rewrite the schema_version table so it contains only `version`."""
    page.evaluate(f"""
        (async () => {{
            await window.__db.run("DELETE FROM schema_version");
            await window.__db.run("INSERT INTO schema_version (version) VALUES ({version})");
        }})()
    """)


def test_dialog_prefilled_with_default_name(page: Page, app_url: str):
    """Save dialog opens with the input prefilled and the extension shown alongside it."""
    _go_to_exercises(page, app_url)
    page.locator('[data-testid="exercise-export-btn"]').click()

    input_ = page.locator('[data-testid="save-file-input"]')
    expect(input_).to_be_visible()
    value = input_.input_value()
    assert re.match(r"^trainus-exercises-\d{4}-\d{2}-\d{2}$", value), f"Unexpected default stem: {value}"
    expect(page.locator('[data-testid="save-file-extension"]')).to_have_text(".json")

    page.locator('[data-testid="save-file-cancel"]').click()


def test_custom_filename_is_used(page: Page, app_url: str):
    """Editing the stem changes the downloaded file's name, keeping the original extension."""
    _go_to_exercises(page, app_url)
    page.locator('[data-testid="exercise-export-btn"]').click()

    page.locator('[data-testid="save-file-input"]').fill("my-custom-export")
    with page.expect_download() as download_info:
        page.locator('[data-testid="save-file-confirm"]').click()
    assert download_info.value.suggested_filename == "my-custom-export.json"


def test_enter_confirms_with_default(page: Page, app_url: str):
    """Pressing Enter in the filename field accepts the prefilled default name."""
    _go_to_exercises(page, app_url)
    page.locator('[data-testid="exercise-export-btn"]').click()

    input_ = page.locator('[data-testid="save-file-input"]')
    default_stem = input_.input_value()
    with page.expect_download() as download_info:
        input_.press("Enter")
    assert download_info.value.suggested_filename == f"{default_stem}.json"


def test_empty_stem_falls_back_to_default(page: Page, app_url: str):
    """Clearing the filename field and saving falls back to the default name."""
    _go_to_exercises(page, app_url)
    page.locator('[data-testid="exercise-export-btn"]').click()

    input_ = page.locator('[data-testid="save-file-input"]')
    default_stem = input_.input_value()
    input_.fill("")
    with page.expect_download() as download_info:
        page.locator('[data-testid="save-file-confirm"]').click()
    assert download_info.value.suggested_filename == f"{default_stem}.json"


def test_cancel_aborts_download(page: Page, app_url: str):
    """Cancelling the save dialog triggers no download."""
    _go_to_exercises(page, app_url)
    page.locator('[data-testid="exercise-export-btn"]').click()
    page.wait_for_selector('[data-testid="save-file-input"]')

    downloaded = []
    page.on("download", lambda d: downloaded.append(d))
    page.locator('[data-testid="save-file-cancel"]').click()
    page.wait_for_timeout(500)
    expect(page.locator('[data-testid="save-file-input"]')).not_to_be_visible()
    assert downloaded == [], "No download should occur when the save dialog is cancelled"


def test_close_button_aborts_download(page: Page, app_url: str):
    """Closing the save dialog via the X button triggers no download."""
    _go_to_exercises(page, app_url)
    page.locator('[data-testid="exercise-export-btn"]').click()
    page.wait_for_selector('[data-testid="save-file-input"]')

    downloaded = []
    page.on("download", lambda d: downloaded.append(d))
    page.locator('[data-testid="modal-close"]').click()
    page.wait_for_timeout(500)
    expect(page.locator('[data-testid="save-file-input"]')).not_to_be_visible()
    assert downloaded == [], "No download should occur when the save dialog is closed"


def test_backup_cancel_does_not_update_last_backup_at(page: Page, app_url: str):
    """Cancelling a database backup save leaves last_backup_at untouched."""
    _go_to_settings(page, app_url)

    before = page.evaluate("async () => await window.__repos.settings.get('last_backup_at')")

    page.locator('[data-testid="settings-download-db"]').click()
    page.wait_for_selector('[data-testid="save-file-cancel"]')
    page.locator('[data-testid="save-file-cancel"]').click()
    page.wait_for_timeout(500)

    after = page.evaluate("async () => await window.__repos.settings.get('last_backup_at')")
    assert after == before, "last_backup_at should not change when the backup save is cancelled"


def test_migration_cancel_keeps_update_disabled(page: Page, app_url: str):
    """Cancelling the forced migration backup leaves the Update button disabled."""
    _wait_for_db(page, app_url)
    _set_db_version(page, 0)

    page.reload()
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-migration') === 'pending'", timeout=15000
    )
    expect(page.locator('[data-testid="migration-update"]')).to_be_disabled()

    page.locator('[data-testid="migration-backup"]').click()
    page.wait_for_selector('[data-testid="save-file-cancel"]')
    page.locator('[data-testid="save-file-cancel"]').click()

    expect(page.locator('[data-testid="migration-update"]')).to_be_disabled()
