*** Settings ***
Documentation    Integration tests for Skill Refresh hooks (feat #168)
...              Covers SkillRefreshResult, SkillRegistry.refresh()/refresh_all(),
...              and MCPRefreshHook notification-to-debounce-to-refresh wiring.
Resource         ${CURDIR}/common.resource
Suite Setup      Setup Test Environment
Suite Teardown   Cleanup Test Environment

*** Variables ***
${HELPER}    ${CURDIR}/helper_skill_refresh.py

*** Test Cases ***
Refresh Single Skill With All Tool Refs Present
    [Documentation]    refresh() returns skill in refreshed list when all tool refs resolve
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    refresh-single-ok    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    refreshed-count: 1
    Should Contain    ${result.stdout}    failed-count: 0
    Should Contain    ${result.stdout}    name-in-refreshed: True
    Should Contain    ${result.stdout}    refresh-single-ok

Refresh Single Skill With Missing Tool Ref
    [Documentation]    refresh() returns skill in failed dict when a tool ref is absent from ToolRegistry
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    refresh-single-missing-tool    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    failed-count: 1
    Should Contain    ${result.stdout}    has-error: True
    Should Contain    ${result.stdout}    error-mentions-missing: True
    Should Contain    ${result.stdout}    refresh-missing-tool-ok

Refresh Single Skill Without Tool Registry
    [Documentation]    refresh() skips validation and counts as refreshed when no ToolRegistry is configured
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    refresh-single-no-registry    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    refreshed-count: 1
    Should Contain    ${result.stdout}    failed-count: 0
    Should Contain    ${result.stdout}    name-in-refreshed: True
    Should Contain    ${result.stdout}    refresh-no-registry-ok

Refresh All Skills With Mixed Results
    [Documentation]    refresh_all() aggregates success and failure across all skills
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    refresh-all-mixed    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    total-refreshed: 1
    Should Contain    ${result.stdout}    total-failed: 1
    Should Contain    ${result.stdout}    ok-refreshed: True
    Should Contain    ${result.stdout}    bad-failed: True
    Should Contain    ${result.stdout}    refresh-all-mixed-ok

Refresh Unknown Skill Raises Error
    [Documentation]    refresh() raises SkillExecutionError for an unregistered skill name
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    refresh-unknown-skill    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    error-type: SkillExecutionError
    Should Contain    ${result.stdout}    error-contains-name: True
    Should Contain    ${result.stdout}    refresh-unknown-ok

Skill Refresh Result Summary Format
    [Documentation]    SkillRefreshResult.to_summary() produces the expected one-liner
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    result-summary    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    has-refreshed: True
    Should Contain    ${result.stdout}    has-failed: True
    Should Contain    ${result.stdout}    has-skipped: True
    Should Contain    ${result.stdout}    result-summary-ok

Skill Refresh Result Merge Combines Two Results
    [Documentation]    SkillRefreshResult.merge() joins refreshed, failed, and skipped lists correctly
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    result-merge    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    total-refreshed: 2
    Should Contain    ${result.stdout}    total-failed: 1
    Should Contain    ${result.stdout}    total-skipped: 1
    Should Contain    ${result.stdout}    a-in-refreshed: True
    Should Contain    ${result.stdout}    c-in-refreshed: True
    Should Contain    ${result.stdout}    b-in-skipped: True
    Should Contain    ${result.stdout}    d-in-failed: True
    Should Contain    ${result.stdout}    result-merge-ok

MCP Refresh Hook Triggers Skill Registry Refresh
    [Documentation]    MCPRefreshHook wires notifications/tools/list_changed to refresh_all()
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    hook-wiring    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    refreshed-at-least-once: True
    Should Contain    ${result.stdout}    hook-wiring-ok

MCP Refresh Hook Debounces Rapid Notifications
    [Documentation]    Multiple tool_list_changed notifications within the debounce window collapse to one refresh
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    hook-debounce    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    debounced-to-one: True
    Should Contain    ${result.stdout}    hook-debounce-ok

MCP Refresh Hook Cancel Prevents Pending Refresh
    [Documentation]    hook.cancel() stops the pending debounced refresh before it fires
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    hook-cancel    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    no-refresh-after-cancel: True
    Should Contain    ${result.stdout}    hook-cancel-ok
