# Copyright 2024 The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.

"""Tests for the management command create_file_store."""

import io

from django.core.management import CommandError
from django.test import TestCase

import yaml

from debusine.db.models import FileStore
from debusine.server.management.commands.tests import call_command
from debusine.test import TestHelpersMixin


class CreateFileStoreCommandTests(TestHelpersMixin, TestCase):
    """Tests for the create_file_store command."""

    def test_create_from_file(self):
        """`create_file_store` creates a new file store (config in file)."""
        name = "test"
        backend = FileStore.BackendChoices.LOCAL
        configuration = {"base_directory": "/nonexistent"}
        configuration_file = self.create_temporary_file(
            contents=yaml.safe_dump(configuration).encode()
        )
        stdout, stderr, exit_code = call_command(
            "create_file_store",
            name,
            backend,
            "--configuration",
            str(configuration_file),
        )

        self.assertEqual(stdout, "")
        self.assertEqual(stderr, "")
        self.assertEqual(exit_code, 0)

        file_store = FileStore.objects.get(name="test")
        self.assertEqual(file_store.backend, backend)
        self.assertEqual(file_store.configuration, configuration)

    def test_create_from_stdin(self):
        """`create_file_store` creates a new file store (config in stdin)."""
        name = "test"
        backend = FileStore.BackendChoices.LOCAL
        configuration = {"base_directory": "/nonexistent"}
        stdout, stderr, exit_code = call_command(
            "create_file_store",
            name,
            backend,
            stdin=io.StringIO(yaml.safe_dump(configuration)),
        )

        self.assertEqual(stdout, "")
        self.assertEqual(stderr, "")
        self.assertEqual(exit_code, 0)

        file_store = FileStore.objects.get(name="test")
        self.assertEqual(file_store.backend, backend)
        self.assertEqual(file_store.configuration, configuration)

    def test_create_external(self):
        """`create_file_store` creates a new external file store."""
        name = "test"
        backend = FileStore.BackendChoices.EXTERNAL_DEBIAN_SUITE
        configuration = {
            "archive_root_url": "https://deb.debian.org/debian",
            "suite": "bookworm",
            "components": ["main"],
        }
        stdout, stderr, exit_code = call_command(
            "create_file_store",
            name,
            backend,
            stdin=io.StringIO(yaml.safe_dump(configuration)),
        )

        self.assertEqual(stdout, "")
        self.assertEqual(stderr, "")
        self.assertEqual(exit_code, 0)

        file_store = FileStore.objects.get(name="test")
        self.assertEqual(file_store.backend, backend)
        self.assertEqual(file_store.configuration, configuration)

    def test_create_invalid_data_yaml(self):
        """`create_file_store` returns error: cannot parse YAML data."""
        with self.assertRaisesRegex(
            CommandError, r"^Error parsing YAML:"
        ) as exc:
            call_command(
                "create_file_store",
                "test",
                FileStore.BackendChoices.LOCAL,
                stdin=io.StringIO(":"),
            )

        self.assertEqual(exc.exception.returncode, 3)

    def test_create_invalid_data(self):
        """`create_file_store` returns error: data is invalid."""
        with self.assertRaisesRegex(
            CommandError, r"^Error creating file store:"
        ) as exc:
            call_command(
                "create_file_store",
                "test",
                FileStore.BackendChoices.EXTERNAL_DEBIAN_SUITE,
                stdin=io.StringIO(yaml.safe_dump({})),
            )

        self.assertEqual(exc.exception.returncode, 3)
        self.assertFalse(FileStore.objects.filter(name="test").exists())

    def test_create_duplicated_name(self):
        """`create_file_store` returns error: duplicated name."""
        FileStore.objects.create(
            name="test",
            backend=FileStore.BackendChoices.LOCAL,
            configuration={},
        )
        with self.assertRaisesRegex(
            CommandError, r"^A file store with this name already exists$"
        ) as exc:
            call_command(
                "create_file_store",
                "test",
                FileStore.BackendChoices.EXTERNAL_DEBIAN_SUITE,
                stdin=io.StringIO(
                    yaml.safe_dump(
                        {
                            "archive_root_url": "https://deb.debian.org/debian",
                            "suite": "bookworm",
                            "components": ["main"],
                        }
                    )
                ),
            )

        self.assertEqual(exc.exception.returncode, 3)
