# 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_collection."""

import io

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

import yaml

from debusine.artifacts.models import CollectionCategory
from debusine.db.models import (
    Collection,
    DEFAULT_WORKSPACE_NAME,
    Workspace,
    default_workspace,
)
from debusine.server.management.commands.tests import call_command
from debusine.test import TestHelpersMixin


class CreateCollectionCommandTests(TestHelpersMixin, TestCase):
    """Tests for the create_collection command."""

    def test_create_collection_from_file(self):
        """`create_collection` creates a new collection (data in file)."""
        name = "test"
        category = CollectionCategory.SUITE
        data = {"may_reuse_versions": True}
        data_file = self.create_temporary_file(
            contents=yaml.safe_dump(data).encode()
        )
        stdout, stderr, exit_code = call_command(
            "create_collection", name, category, "--data", str(data_file)
        )

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

        collection = Collection.objects.get(name=name, category=category)
        self.assertEqual(collection.workspace.name, DEFAULT_WORKSPACE_NAME)
        self.assertEqual(collection.data, data)

    def test_create_collection_from_stdin(self):
        """`create_collection` creates a new collection (data in file)."""
        name = "test"
        category = CollectionCategory.SUITE
        data = {"may_reuse_versions": True}
        stdout, stderr, exit_code = call_command(
            "create_collection",
            name,
            category,
            stdin=io.StringIO(yaml.safe_dump(data)),
        )

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

        collection = Collection.objects.get(name=name, category=category)
        self.assertEqual(collection.workspace.name, DEFAULT_WORKSPACE_NAME)
        self.assertEqual(collection.data, data)

    def test_create_collection_empty_data(self):
        """`create_collection` defaults data to {}."""
        name = "test"
        category = CollectionCategory.ENVIRONMENTS
        stdout, stderr, exit_code = call_command(
            "create_collection", name, category, stdin=io.StringIO()
        )

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

        collection = Collection.objects.get(name=name, category=category)
        self.assertEqual(collection.data, {})

    def test_create_collection_different_workspace(self):
        """`create_collection` can use a non-default workspace."""
        name = "test"
        category = CollectionCategory.ENVIRONMENTS
        workspace_name = "test-workspace"
        Workspace.objects.create_with_name(workspace_name)
        stdout, stderr, exit_code = call_command(
            "create_collection",
            name,
            category,
            "--workspace",
            workspace_name,
            stdin=io.StringIO(),
        )

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

        collection = Collection.objects.get(name=name, category=category)
        self.assertEqual(collection.workspace.name, workspace_name)

    def test_create_collection_invalid_data_yaml(self):
        """`create_collection` returns error: cannot parse YAML data."""
        with self.assertRaisesRegex(
            CommandError, r"^Error parsing YAML:"
        ) as exc:
            call_command(
                "create_collection",
                "test",
                CollectionCategory.ENVIRONMENTS,
                stdin=io.StringIO(":"),
            )

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

    def test_create_collection_nonexistent_workspace(self):
        """`create_collection` returns error: workspace not found."""
        with self.assertRaisesRegex(
            CommandError, r'^Workspace "nonexistent" not found$'
        ) as exc:
            call_command(
                "create_collection",
                "test",
                CollectionCategory.ENVIRONMENTS,
                "--workspace",
                "nonexistent",
                stdin=io.StringIO(),
            )

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

    def test_create_collection_duplicated_name_and_category(self):
        """`create_collection` returns error: duplicated name and category."""
        Collection.objects.create(
            name="test",
            category=CollectionCategory.SUITE,
            workspace=default_workspace(),
            data={},
        )
        with self.assertRaisesRegex(
            CommandError,
            r"^A collection with this name and category already exists$",
        ) as exc:
            call_command(
                "create_collection",
                "test",
                CollectionCategory.SUITE,
                stdin=io.StringIO(yaml.safe_dump({"may_reuse_versions": True})),
            )

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