from unittest.mock import patch, Mock
from opnsense_cli.commands.plugin.haproxy.backend import backend
from opnsense_cli.commands.test_base import CommandTestCase
import os


class TestHaproxyBackendCommands(CommandTestCase):
    def setUp(self):
        self._api_data_fixtures_reconfigure_OK = {"status": "ok"}
        self._api_data_fixtures_reconfigure_FAILED = {"status": "failed"}
        self._api_data_fixtures_configtest_OK = {"result": "Configuration file is valid\n\n\n"}
        self._api_data_fixtures_configtest_FAILED = {"result": "Configuration file is invalid\n\n\n"}
        self._api_data_fixtures_create_OK = {"result": "saved", "uuid": "85282721-934c-42be-ba4d-a93cbfda26af"}
        self._api_data_fixtures_create_ERROR = {
            "result": "failed",
            "validations": {"backend.tuning_retries": ["Please specify a value between 1 and 100."]},
        }
        self._api_data_fixtures_update_OK = {"result": "saved"}
        self._api_data_fixtures_update_NOT_EXISTS = {"result": "failed"}
        self._api_data_fixtures_delete_NOT_FOUND = {"result": "not found"}
        self._api_data_fixtures_delete_OK = {"result": "deleted"}
        self._api_data_fixtures_list_EMPTY = {"haproxy": {"backends": {"backend": []}}}
        self._api_data_fixtures_list = self._read_json_fixture("fixtures/model_data.json", base_dir=os.path.dirname(__file__))
        self._api_client_args_fixtures = ["api_key", "api_secret", "https://127.0.0.1/api", True, "~/.opn-cli/ca.pem", 60]

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_list(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_list,
            ],
            backend,
            ["list", "-o", "plain", "-c", "uuid,name,Servers,Resolver,Healthcheck,Mailer,Users,Groups,Actions,Errorfiles"],
        )

        self.assertIn(
            (
                "5d17779f-1407-4cdf-a616-b7024bea4448 pool1 server1,server2 resolver1 http_head alert_to_myself   "
                "my_rule custom_error_500\n"
                "2c57ff97-10df-41a1-8a02-ab2fd1a4a651 pool2 server2,server4  http_head     \n"
                "fee6bae9-8168-46bc-a6d1-c88838a1b3ec pool3 my_new_testserver,my_new_testserver       \n"
                "45e81a82-0c52-4739-a660-0cb0dcd1f409 pool4        \n"
            ),
            result.output,
        )

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_list_EMPTY(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_list_EMPTY,
            ],
            backend,
            ["list", "-o", "plain"],
        )

        self.assertIn("", result.output)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_show_NOT_FOUND(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_list,
            ],
            backend,
            ["show", "b468c719-89db-45a8-bd02-b081246dc002"],
        )
        self.assertIn("", result.output)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_show_EMPTY_STRING(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_list,
            ],
            backend,
            ["show", ""],
        )
        self.assertIn("", result.output)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_show(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_list,
            ],
            backend,
            [
                "show",
                "2c57ff97-10df-41a1-8a02-ab2fd1a4a651",
                "-o",
                "plain",
                "-c",
                "uuid,name,Servers,Resolver,Healthcheck,Mailer,Users,Groups,Actions,Errorfiles",
            ],
        )

        self.assertIn(("2c57ff97-10df-41a1-8a02-ab2fd1a4a651 pool2 server2,server4  http_head     \n"), result.output)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_create_OK(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_list,
                self._api_data_fixtures_create_OK,
                self._api_data_fixtures_configtest_OK,
                self._api_data_fixtures_reconfigure_OK,
            ],
            backend,
            [
                "create",
                "my_test_backend",
                "--no-enabled",
                "--description",
                "test",
                "--mode",
                "tcp",
                "--algorithm",
                "roundrobin",
                "--proxyProtocol",
                "v2",
                "--linkedServers",
                "server1,server2",
                "--linkedResolver",
                "resolver1",
                "--healthCheck",
                "http_head",
                "--linkedMailer",
                "alert_to_myself",
                "--basicAuthUsers",
                "user1",
                "--basicAuthGroups",
                "group1",
                "--linkedActions",
                "my_rule",
                "--linkedErrorfiles",
                "custom_error_500",
                "--resolverOpts",
                "allow-dup-ip",
                "--resolverOpts",
                "prevent-dup-ip",
                "--ba_advertised_protocols",
                "h2",
                "--ba_advertised_protocols",
                "http11",
                "--ba_advertised_protocols",
                "http10",
            ],
        )

        self.assertIn(("saved \n"), result.output)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_create_ERROR(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_create_ERROR,
                self._api_data_fixtures_configtest_OK,
                self._api_data_fixtures_reconfigure_OK,
            ],
            backend,
            [
                "create",
                "my_test_backend",
                "--tuning_retries",
                10000,
            ],
        )

        self.assertIn(
            (
                "Error: {'result': 'failed', "
                "'validations': {'backend.tuning_retries': ['Please specify a value between 1 and 100.']}}\n"
            ),
            result.output,
        )
        self.assertEqual(1, result.exit_code)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_create_UNRESOLVED(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_list,
                self._api_data_fixtures_create_ERROR,
                self._api_data_fixtures_configtest_OK,
                self._api_data_fixtures_reconfigure_OK,
            ],
            backend,
            [
                "create",
                "my_test_backend",
                "--linkedServers",
                "non_existing_server",
            ],
        )

        self.assertIn(("Error: Could not find uuid for $.haproxy.servers.server: ['non_existing_server']\n"), result.output)
        self.assertEqual(1, result.exit_code)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_update_OK(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_update_OK,
                self._api_data_fixtures_configtest_OK,
                self._api_data_fixtures_reconfigure_OK,
            ],
            backend,
            [
                "update",
                "85282721-934c-42be-ba4d-a93cbfda26af",
                "--enabled",
            ],
        )

        self.assertIn(("saved \n"), result.output)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_update_NOT_EXISTS(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_update_NOT_EXISTS,
                self._api_data_fixtures_configtest_OK,
                self._api_data_fixtures_reconfigure_OK,
            ],
            backend,
            [
                "update",
                "99282721-934c-42be-ba4d-a93cbfda2644",
                "--no-enabled",
            ],
        )

        self.assertIn(("Error: {'result': 'failed'}\n"), result.output)
        self.assertEqual(1, result.exit_code)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_delete_OK(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_delete_OK,
                self._api_data_fixtures_configtest_OK,
                self._api_data_fixtures_reconfigure_OK,
            ],
            backend,
            [
                "delete",
                "85282721-934c-42be-ba4d-a93cbfda26af",
            ],
        )

        self.assertIn(("deleted \n"), result.output)

    @patch("opnsense_cli.commands.plugin.haproxy.backend.ApiClient.execute")
    def test_delete_NOT_FOUND(self, api_response_mock: Mock):
        result = self._opn_cli_command_result(
            api_response_mock,
            [
                self._api_data_fixtures_delete_NOT_FOUND,
                self._api_data_fixtures_configtest_OK,
                self._api_data_fixtures_reconfigure_OK,
            ],
            backend,
            [
                "delete",
                "99282721-934c-42be-ba4d-a93cbfda2644",
            ],
        )

        self.assertIn("Error: {'result': 'not found'}\n", result.output)
        self.assertEqual(1, result.exit_code)
