*** Settings ***
Resource    ${CURDIR}/../resources/common.resource
Resource    ${CURDIR}/../resources/auth.resource

# Use unique X-Forwarded-For to bypass per-IP rate limit across test runs.
# Rate limit: 10 imports / IP / hour. Overridden at runtime via header.
Suite Setup    Login As Admin

*** Test Cases ***
Manual Blocklist Import Completes Without Error
    [Documentation]    Verifies the full import pipeline:
    ...    UI button click → async backend task → HTTP fetch → DB write → UI log entry.
    ...
    ...    - Uses local mock server when external network is unavailable.
    ...    - Rate limit bypassed via X-Forwarded-For header.
    ...    - Import "completes successfully" is distinct from "bans were added".
    [Teardown]    Cleanup Mock Server

    # Pre-condition: ensure at least one source is configured.
    ${sess}=    Login Via HTTP
    Ensure Blocklist Source Exists    ${sess}

    # Determine if external network is reachable.
    ${no_internet}=    Evaluate    __import__("socket").gethostbyname("one.one.one.one") is None    modules=socket
    IF    ${no_internet}
        Start Local Mock Server
    END

    # Navigate to blocklists page and locate the import button.
    Go To    ${FRONTEND_URL}/blocklists
    Wait For Elements State    css=button[data-testid="blocklist-import-button"]    visible    timeout=15s

    # Record current log entry count before triggering import.
    ${headers}=    Create Dictionary    X-Forwarded-For    10.0.0.99
    ${resp_before}=    GET On Session    ${sess}    /api/v1/blocklists/log    headers=${headers}    expected_status=200
    ${log_count_before}=    Get Length    ${resp_before.json()}[items]

    # Trigger the import via the manual import button.
    Click    css=button[data-testid="blocklist-import-button"]

    # Wait for import to finish: button re-enabled or success toast appears.
    Wait For Elements State    css=button[data-testid="blocklist-import-button"]    enabled    timeout=45s

    # Assert no error banner in the UI.
    ${error_visible}=    Run Keyword And Return Status    Get Text    css=[data-testid="error-banner"]    contains    error
    IF    ${error_visible}
        ${error_text}=    Get Text    css=[data-testid="error-banner"]
        Fatal Error    Import error banner appeared: ${error_text}
    END

    # Verify the log has a new entry (import ran, regardless of bans added).
    ${resp_after}=    GET On Session    ${sess}    /api/v1/blocklists/log    headers=${headers}    expected_status=200
    ${log_count_after}=    Get Length    ${resp_after.json()}[items]
    Should Be True    ${log_count_after} > ${log_count_before}
    Log    Import completed. Log entries: ${log_count_before} → ${log_count_after}


*** Keywords ***
Ensure Blocklist Source Exists
    [Arguments]    ${sess}
    [Documentation]    Guarantee at least one blocklist source exists.
    ...    If GET /api/v1/blocklists returns an empty list, a minimal local-file
    ...    source is added so the import test has a target.
    ${headers}=    Create Dictionary    X-Forwarded-For    10.0.0.99
    ${resp}=    GET On Session    ${sess}    /api/v1/blocklists    headers=${headers}    expected_status=200
    ${sources}=    Set Variable    ${resp.json()}[sources]
    ${count}=    Get Length    ${sources}

    IF    ${count} == 0
        # No sources configured — add a minimal entry pointing to the mock server.
        # The mock server serves test.txt from the e2e directory.
        ${payload}=    Create Dictionary
        ...    name=Local Mock Source
        ...    url=http://127.0.0.1:8765/test_blocklist.txt
        ...    enabled=${TRUE}
        POST On Session    ${sess}    /api/v1/blocklists    json=${payload}    headers=${headers}    expected_status=201
        Log    Created local mock blocklist source.
    ELSE
        Log    Blocklist source already exists — using first available.
    END

Start Local Mock Server
    [Documentation]    Start a minimal Python HTTP server on port 8765 to serve a test blocklist file.
    ...    The test.txt file contains one IP per line in plain-text format (fail2ban plain list).
    ${mock_file}=    Set Variable    ${CURDIR}/../../test_blocklist.txt
    ${file_exists}=    OperatingSystem.File Should Exist    ${mock_file}
    Start Process    python    -m http.server    8765    --bind    127.0.0.1    --directory    ${CURDIR}/../../    alias=mockserver
    ...    stdout=PIPE    stderr=STDOUT
    Sleep    2s
    Log    Local mock HTTP server started on 127.0.0.1:8765.

Cleanup Mock Server
    [Documentation]    Stop the mock HTTP server started by Start Local Mock Server.
    ${status}=    Run Keyword And Return Status    Terminate Process    mockserver
    Log    Mock server cleanup: ${status}