import unittest

from ai_web_agent_console.query_contracts import (
    append_query_contract_guidance,
    evidence_contract_report,
    matching_query_contracts,
)


def test_leave_eligibility_question_selects_external_contract():
    contracts = matching_query_contracts(
        "직원 E9999의 연차 잔여와 신청 가능 여부를 알려줘",
        "search_hr_data",
    )

    assert [contract["id"] for contract in contracts] == [
        "leave_balance_eligibility"
    ]


def test_unrelated_tool_does_not_receive_leave_contract():
    contracts = matching_query_contracts(
        "직원 E9999의 연차 잔여를 알려줘",
        "search_carrier_performance",
    )

    assert contracts == ()


def test_incomplete_result_cannot_be_interpreted_as_zero_balance():
    contracts = matching_query_contracts(
        "직원 E9999의 연차 사용 가능 여부를 알려줘",
        "search_hr_data",
    )
    evidence = {
        "result": (
            'DATA_RESULT: {"items":[{"EMPLOYEE_CODE":"E9999",'
            '"REMAINING_DAYS":0}]}'
        )
    }

    report = evidence_contract_report(contracts, evidence)

    assert report[0]["satisfied"] is False
    assert "AVAILABLE_REMAINING_DAYS" in report[0]["missing_fields"]
    assert "LEAVE_YEAR" in report[0]["missing_fields"]


def test_complete_database_row_satisfies_contract_without_fixture_values():
    contracts = matching_query_contracts(
        "직원 E9999의 연차 신청 가능 여부를 알려줘",
        "search_hr_data",
    )
    evidence = {
        "result": (
            'DATA_RESULT\n{"items":[{"EMPLOYEE_CODE":"E9999",'
            '"LEAVE_YEAR":2031,"ANNUAL_ENTITLEMENT":17,'
            '"CARRYOVER_DAYS":2,"USED_DAYS":4,"PENDING_DAYS":1,'
            '"AVAILABLE_REMAINING_DAYS":14}]}'
        )
    }

    report = evidence_contract_report(contracts, evidence)

    assert report[0]["satisfied"] is True
    assert report[0]["validated_record"]["LEAVE_YEAR"] == 2031
    assert report[0]["validated_record"]["AVAILABLE_REMAINING_DAYS"] == 14


def test_conflicting_computed_value_fails_contract():
    contracts = matching_query_contracts(
        "직원 E9999의 연차 신청 가능 여부를 알려줘",
        "search_hr_data",
    )
    evidence = {
        "result": (
            'DATA_RESULT\n{"items":[{"EMPLOYEE_CODE":"E9999",'
            '"LEAVE_YEAR":2031,"ANNUAL_ENTITLEMENT":17,'
            '"CARRYOVER_DAYS":2,"USED_DAYS":4,"PENDING_DAYS":1,'
            '"AVAILABLE_REMAINING_DAYS":0}]}'
        )
    }

    report = evidence_contract_report(contracts, evidence)

    assert report[0]["satisfied"] is False
    assert report[0]["computed_field_checks"][0]["expected"] == "14"
    assert report[0]["computed_field_checks"][0]["actual"] == "0"


def test_historical_period_rejects_yes_no_decision_and_missing_counts():
    contracts = matching_query_contracts(
        "직원 E9999의 과거 연차 신청 가능 여부를 알려줘",
        "search_hr_data",
    )
    evidence = {
        "result": (
            'DATA_RESULT\n{"items":[{"EMPLOYEE_CODE":"E9999",'
            '"LEAVE_YEAR":2031,"ANNUAL_ENTITLEMENT":17,'
            '"CARRYOVER_DAYS":2,"USED_DAYS":4,"PENDING_DAYS":1,'
            '"AVAILABLE_REMAINING_DAYS":14,'
            '"REQUEST_PERIOD_LABEL":"HISTORICAL_REQUEST_PERIOD",'
            '"CAN_APPLY":"YES","INCLUSIVE_CALENDAR_DAYS":11}]}'
        )
    }

    report = evidence_contract_report(contracts, evidence)

    assert report[0]["satisfied"] is False
    failed = {
        check["check"]
        for check in report[0]["temporal_contract_checks"]
        if not check["satisfied"]
    }
    assert failed == {
        "past_period_decision",
        "no_past_period_yes_no_decision",
        "date_range_counts",
    }


def test_historical_period_contract_accepts_non_decision_status():
    contracts = matching_query_contracts(
        "직원 E9999의 과거 연차 신청 가능 여부를 알려줘",
        "search_hr_data",
    )
    evidence = {
        "result": (
            'DATA_RESULT\n{"items":[{"EMPLOYEE_CODE":"E9999",'
            '"LEAVE_YEAR":2031,"ANNUAL_ENTITLEMENT":17,'
            '"CARRYOVER_DAYS":2,"USED_DAYS":4,"PENDING_DAYS":1,'
            '"AVAILABLE_REMAINING_DAYS":14,'
            '"REQUEST_PERIOD_LABEL":"HISTORICAL_REQUEST_PERIOD",'
            '"APPLICATION_DECISION_STATUS":'
            '"NOT_APPLICABLE_FOR_HISTORICAL_PERIOD",'
            '"INCLUSIVE_CALENDAR_DAYS":11,'
            '"MONDAY_TO_FRIDAY_DAYS":7}]}'
        )
    }

    report = evidence_contract_report(contracts, evidence)

    assert report[0]["satisfied"] is True


def test_guidance_is_appended_from_json_contract():
    guided = append_query_contract_guidance(
        "직원 E9999의 휴가 잔여를 조회해줘",
        original_question="직원 E9999의 휴가 잔여를 조회해줘",
        tool_name="search_hr_data",
    )

    assert '"id":"leave_balance_eligibility"' in guided
    assert "AVAILABLE_REMAINING_DAYS" in guided


class QueryContractTest(unittest.TestCase):
    test_leave_eligibility_question_selects_external_contract = staticmethod(
        test_leave_eligibility_question_selects_external_contract
    )
    test_unrelated_tool_does_not_receive_leave_contract = staticmethod(
        test_unrelated_tool_does_not_receive_leave_contract
    )
    test_incomplete_result_cannot_be_interpreted_as_zero_balance = staticmethod(
        test_incomplete_result_cannot_be_interpreted_as_zero_balance
    )
    test_complete_database_row_satisfies_contract_without_fixture_values = (
        staticmethod(test_complete_database_row_satisfies_contract_without_fixture_values)
    )
    test_conflicting_computed_value_fails_contract = staticmethod(
        test_conflicting_computed_value_fails_contract
    )
    test_historical_period_rejects_yes_no_decision_and_missing_counts = (
        staticmethod(test_historical_period_rejects_yes_no_decision_and_missing_counts)
    )
    test_historical_period_contract_accepts_non_decision_status = staticmethod(
        test_historical_period_contract_accepts_non_decision_status
    )
    test_guidance_is_appended_from_json_contract = staticmethod(
        test_guidance_is_appended_from_json_contract
    )
