import boto3
import pytest
from botocore.exceptions import ClientError

from moto import mock_aws


@mock_aws
def test_create_health_check():
    client = boto3.client("route53", region_name="us-east-1")

    response = client.create_health_check(
        CallerReference="test-route53-health-HealthCheck-asdf",
        HealthCheckConfig={
            "IPAddress": "93.184.216.34",
            "Port": 80,
            "Type": "HTTP",
            "ResourcePath": "/",
            "FullyQualifiedDomainName": "example.com",
            "RequestInterval": 10,
            "FailureThreshold": 2,
        },
    )
    assert response["ResponseMetadata"]["HTTPStatusCode"] == 201
    #
    check = response["HealthCheck"]
    assert "Id" in check
    assert check["CallerReference"] == "test-route53-health-HealthCheck-asdf"
    assert "HealthCheckConfig" in check
    #
    config = check["HealthCheckConfig"]
    assert config["IPAddress"] == "93.184.216.34"
    assert config["Port"] == 80
    assert config["Type"] == "HTTP"
    assert config["ResourcePath"] == "/"
    assert config["FullyQualifiedDomainName"] == "example.com"
    assert config["RequestInterval"] == 10
    assert config["FailureThreshold"] == 2
    assert config["MeasureLatency"] is False
    assert config["Inverted"] is False
    assert config["Disabled"] is False
    assert config["EnableSNI"] is False

    assert "ChildHealthChecks" not in config
    assert "HealthThreshold" not in config


@mock_aws
def test_create_health_check_with_additional_options():
    client = boto3.client("route53", region_name="us-east-1")

    response = client.create_health_check(
        CallerReference="test-route53-health-HealthCheck-asdf",
        HealthCheckConfig={
            "IPAddress": "93.184.216.34",
            "Port": 80,
            "Type": "HTTP",
            "ResourcePath": "/",
            "FullyQualifiedDomainName": "example.com",
            "SearchString": "a good response",
            "RequestInterval": 10,
            "FailureThreshold": 2,
            "MeasureLatency": True,
            "Inverted": True,
            "Disabled": True,
            "EnableSNI": True,
        },
    )
    assert response["ResponseMetadata"]["HTTPStatusCode"] == 201
    #
    check = response["HealthCheck"]
    assert check["CallerReference"] == "test-route53-health-HealthCheck-asdf"
    assert check["HealthCheckVersion"] == 1
    assert "HealthCheckConfig" in check
    #
    config = check["HealthCheckConfig"]
    assert check["HealthCheckConfig"]["SearchString"] == "a good response"
    assert config["MeasureLatency"] is True
    assert config["Inverted"] is True
    assert config["Disabled"] is True
    assert config["EnableSNI"] is True


@mock_aws
def test_create_calculated_health_check():
    client = boto3.client("route53", region_name="us-east-1")

    response = client.create_health_check(
        CallerReference="test-route53-health-HealthCheck-ZHV123",
        HealthCheckConfig={
            "Type": "CALCULATED",
            "Inverted": False,
            "Disabled": False,
            "HealthThreshold": 1,
        },
    )

    check = response["HealthCheck"]
    assert "Id" in check
    assert check["CallerReference"] == "test-route53-health-HealthCheck-ZHV123"
    #
    config = check["HealthCheckConfig"]
    assert config["Type"] == "CALCULATED"
    assert config["Inverted"] is False
    assert config["Disabled"] is False
    assert config["HealthThreshold"] == 1
    #
    assert "IPAddress" not in config
    assert "Port" not in config
    assert "ResourcePath" not in config
    assert "FullyQualifiedDomainName" not in config
    assert "RequestInterval" not in config
    assert "FailureThreshold" not in config
    assert "MeasureLatency" not in config


@mock_aws
def test_create_calculated_health_check_with_children():
    client = boto3.client("route53", region_name="us-east-1")

    child1 = client.create_health_check(
        CallerReference="test-route53-health-HealthCheck-child1",
        HealthCheckConfig={
            "Type": "CALCULATED",
            "Inverted": False,
            "Disabled": False,
            "HealthThreshold": 1,
        },
    )

    child2 = client.create_health_check(
        CallerReference="test-route53-health-HealthCheck-child2",
        HealthCheckConfig={
            "Type": "CALCULATED",
            "Inverted": False,
            "Disabled": False,
            "HealthThreshold": 1,
        },
    )

    parent = client.create_health_check(
        CallerReference="test-route53-health-HealthCheck-parent",
        HealthCheckConfig={
            "Type": "CALCULATED",
            "Inverted": False,
            "Disabled": False,
            "HealthThreshold": 1,
            "ChildHealthChecks": [
                child1["HealthCheck"]["Id"],
                child2["HealthCheck"]["Id"],
            ],
        },
    )

    check = parent["HealthCheck"]
    assert "Id" in check
    assert check["CallerReference"] == "test-route53-health-HealthCheck-parent"
    #
    config = check["HealthCheckConfig"]
    assert config["Type"] == "CALCULATED"
    assert config["Inverted"] is False
    assert config["Disabled"] is False
    assert config["HealthThreshold"] == 1
    assert config["ChildHealthChecks"] == [
        child1["HealthCheck"]["Id"],
        child2["HealthCheck"]["Id"],
    ]


@mock_aws
def test_get_health_check():
    client = boto3.client("route53", region_name="us-east-1")

    hc_id = client.create_health_check(
        CallerReference="callref",
        HealthCheckConfig={
            "Type": "CALCULATED",
            "Inverted": False,
            "Disabled": False,
            "HealthThreshold": 1,
        },
    )["HealthCheck"]["Id"]

    resp = client.get_health_check(HealthCheckId=hc_id)["HealthCheck"]
    assert resp["Id"] == hc_id
    assert resp["CallerReference"] == "callref"
    assert resp["HealthCheckVersion"] == 1


@mock_aws
def test_get_unknown_health_check():
    client = boto3.client("route53", region_name="us-east-1")

    with pytest.raises(ClientError) as exc:
        client.get_health_check(HealthCheckId="unknown")
    err = exc.value.response["Error"]
    assert err["Code"] == "NoSuchHealthCheck"
    assert err["Message"] == "A health check with id unknown does not exist."


@mock_aws
def test_list_health_checks():
    conn = boto3.client("route53", region_name="us-east-1")

    assert len(conn.list_health_checks()["HealthChecks"]) == 0

    check = conn.create_health_check(
        CallerReference="?",
        HealthCheckConfig={
            "IPAddress": "10.0.0.25",
            "Port": 80,
            "Type": "HTTP",
            "ResourcePath": "/",
            "FullyQualifiedDomainName": "example.com",
            "SearchString": "a good response",
            "RequestInterval": 10,
            "FailureThreshold": 2,
        },
    )["HealthCheck"]

    assert conn.list_health_checks()["HealthChecks"] == [check]


@mock_aws
def test_delete_health_checks():
    conn = boto3.client("route53", region_name="us-east-1")

    assert len(conn.list_health_checks()["HealthChecks"]) == 0

    check = conn.create_health_check(
        CallerReference="?",
        HealthCheckConfig={
            "IPAddress": "10.0.0.25",
            "Port": 80,
            "Type": "HTTP",
            "ResourcePath": "/",
            "FullyQualifiedDomainName": "example.com",
            "SearchString": "a good response",
            "RequestInterval": 10,
            "FailureThreshold": 2,
        },
    )["HealthCheck"]

    conn.delete_health_check(HealthCheckId=check["Id"])

    checks = conn.list_health_checks()["HealthChecks"]
    assert len(checks) == 0


@mock_aws
@pytest.mark.parametrize("original_value", [True, False])
def test_update_health_check(original_value):
    client = boto3.client("route53", region_name="us-east-1")

    hc_id = client.create_health_check(
        CallerReference="callref",
        HealthCheckConfig={
            "Type": "CALCULATED",
            "Inverted": original_value,
            "Disabled": original_value,
            "HealthThreshold": 1,
        },
    )["HealthCheck"]["Id"]

    client.update_health_check(
        HealthCheckId=hc_id,
        IPAddress="0.0.0.0",
        Port=80,
        ResourcePath="rp",
        FullyQualifiedDomainName="example.com",
        SearchString="search",
        FailureThreshold=123,
        Inverted=not original_value,
        Disabled=not original_value,
        EnableSNI=not original_value,
        HealthThreshold=13,
        ChildHealthChecks=["child"],
        Regions=["us-east-1", "us-east-2", "us-west-1"],
    )

    config = client.get_health_check(HealthCheckId=hc_id)["HealthCheck"][
        "HealthCheckConfig"
    ]
    assert config["Type"] == "CALCULATED"
    assert config["ResourcePath"] == "rp"
    assert config["FullyQualifiedDomainName"] == "example.com"
    assert config["SearchString"] == "search"
    assert config["Inverted"] is not original_value
    assert config["Disabled"] is not original_value
    assert config["EnableSNI"] is not original_value
    assert config["ChildHealthChecks"] == ["child"]
    assert config["Regions"] == ["us-east-1", "us-east-2", "us-west-1"]


@mock_aws
def test_health_check_status():
    client = boto3.client("route53", region_name="us-east-1")

    hc_id = client.create_health_check(
        CallerReference="callref",
        HealthCheckConfig={
            "Type": "CALCULATED",
            "Inverted": False,
            "Disabled": False,
            "HealthThreshold": 1,
        },
    )["HealthCheck"]["Id"]

    resp = client.get_health_check_status(HealthCheckId=hc_id)
    assert len(resp["HealthCheckObservations"]) == 1

    observation = resp["HealthCheckObservations"][0]
    assert observation["Region"] == "us-east-1"
    assert observation["IPAddress"] == "127.0.13.37"
    assert "StatusReport" in observation
    assert (
        observation["StatusReport"]["Status"]
        == "Success: HTTP Status Code: 200. Resolved IP: 127.0.13.37. OK"
    )

    with pytest.raises(ClientError) as exc:
        client.get_health_check_status(HealthCheckId="bad-id")

    err = exc.value.response["Error"]
    assert err["Code"] == "NoSuchHealthCheck"
    assert err["Message"] == "A health check with id bad-id does not exist."
