#!/usr/bin/env python3
# Copyright 2022 Canonical Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# For those usages not covered by the Apache License, Version 2.0 please
# contact: legal@canonical.com
#
# To get in touch with the maintainers, please contact:
# osm-charmers@lists.launchpad.net
#
# Learn more about testing at: https://juju.is/docs/sdk/testing

import pytest
from ops.model import ActiveStatus, BlockedStatus
from ops.testing import Harness
from pytest_mock import MockerFixture

from charm import CharmError, OsmMonCharm, check_service_active

container_name = "mon"
service_name = "mon"
url_configs = ["grafana-url", "prometheus-url"]


@pytest.fixture
def harness(mocker: MockerFixture):
    mocker.patch("charm.KubernetesServicePatch", lambda x, y: None)
    harness = Harness(OsmMonCharm)
    harness.begin()
    harness.container_pebble_ready(container_name)
    yield harness
    harness.cleanup()


def _set_mandatory_config(harness: Harness):
    harness.update_config(
        {
            "grafana-url": "http://grafana:1234",
            "grafana-user": "user",
            "grafana-password": "password",
            "prometheus-url": "http://someurl",
        }
    )


def test_default_config_is_invalid_charm_is_blocked(harness: Harness):
    harness.charm.on.config_changed.emit()
    assert isinstance(harness.charm.unit.status, BlockedStatus)
    assert (
        "need grafana-url, grafana-user, grafana-password, prometheus-url config"
        == harness.charm.unit.status.message
    )


def test_missing_relations(harness: Harness):
    _set_mandatory_config(harness)
    harness.charm.on.config_changed.emit()
    assert isinstance(harness.charm.unit.status, BlockedStatus)
    assert all(
        relation in harness.charm.unit.status.message
        for relation in ["mongodb", "kafka", "prometheus", "keystone"]
    )


@pytest.mark.parametrize("config_param", url_configs)
def test_url_config_without_schema_block_status(harness: Harness, config_param):
    _set_mandatory_config(harness)
    _add_relations(harness)
    harness.update_config({config_param: "foo.com"})
    assert isinstance(harness.charm.unit.status, BlockedStatus)
    assert (
        f"Invalid value for {config_param} config: 'foo.com'" in harness.charm.unit.status.message
    )


@pytest.mark.parametrize("config_param", url_configs)
def test_url_config_with_port_without_schema_block_status(harness: Harness, config_param):
    _set_mandatory_config(harness)
    _add_relations(harness)
    harness.update_config({config_param: "foo.com:9090"})
    assert isinstance(harness.charm.unit.status, BlockedStatus)
    assert (
        f"Invalid value for {config_param} config: 'foo.com:9090'"
        in harness.charm.unit.status.message
    )


@pytest.mark.parametrize("config_param", url_configs)
def test_url_config_without_port_is_valid(harness: Harness, config_param):
    _set_mandatory_config(harness)
    _add_relations(harness)
    harness.update_config({config_param: "http://foo"})
    assert harness.charm.unit.status == ActiveStatus()


@pytest.mark.parametrize("config_param", url_configs)
def test_url_config_with_port_is_valid(harness: Harness, config_param):
    _set_mandatory_config(harness)
    _add_relations(harness)
    harness.update_config({config_param: "http://foo:90"})
    assert harness.charm.unit.status == ActiveStatus()


def test_ready(harness: Harness):
    _set_mandatory_config(harness)
    _add_relations(harness)
    assert harness.charm.unit.status == ActiveStatus()


def test_container_stops_after_relation_broken(harness: Harness):
    _set_mandatory_config(harness)
    harness.charm.on[container_name].pebble_ready.emit(container_name)
    container = harness.charm.unit.get_container(container_name)
    relation_ids = _add_relations(harness)
    check_service_active(container, service_name)
    harness.remove_relation(relation_ids[0])
    with pytest.raises(CharmError):
        check_service_active(container, service_name)


def _add_relations(harness: Harness):
    relation_ids = []
    # Add mongo relation
    relation_id = harness.add_relation("mongodb", "mongodb")
    harness.add_relation_unit(relation_id, "mongodb/0")
    harness.update_relation_data(
        relation_id,
        "mongodb",
        {"uris": "mongodb://:1234", "username": "user", "password": "password"},
    )
    relation_ids.append(relation_id)
    # Add kafka relation
    relation_id = harness.add_relation("kafka", "kafka")
    harness.add_relation_unit(relation_id, "kafka/0")
    harness.update_relation_data(relation_id, "kafka", {"host": "kafka", "port": "9092"})
    relation_ids.append(relation_id)
    # Add prometheus relation
    relation_id = harness.add_relation("metrics-endpoint", "prometheus")
    relation_ids.append(relation_id)
    # Add keystone relation
    relation_id = harness.add_relation("keystone", "keystone")
    harness.add_relation_unit(relation_id, "keystone/0")
    harness.update_relation_data(
        relation_id,
        "keystone",
        {
            "host": "host",
            "port": "port",
            "user_domain_name": "user_domain_name",
            "project_domain_name": "project_domain_name",
            "username": "username",
            "password": "password",
            "service": "service",
            "keystone_db_password": "keystone_db_password",
            "region_id": "region_id",
            "admin_username": "admin_username",
            "admin_password": "admin_password",
            "admin_project_name": "admin_project_name",
        },
    )
    relation_ids.append(relation_id)
    return relation_ids
