import allure
import pytest
from frostfs_testlib import reporter
from frostfs_testlib.resources.wellknown_acl import PRIVATE_ACL_F
from frostfs_testlib.steps.cli.container import (
    create_container,
    delete_container,
    get_container,
    list_containers,
    wait_for_container_creation,
    wait_for_container_deletion,
)
from frostfs_testlib.storage.dataclasses.wallet import WalletInfo
from frostfs_testlib.testing.cluster_test_base import ClusterTestBase

from ...helpers.utility import placement_policy_from_container


@pytest.mark.nightly
@pytest.mark.sanity
@pytest.mark.container
class TestContainer(ClusterTestBase):
    @allure.title("Create container (name={name})")
    @pytest.mark.parametrize("name", ["", "test-container"], ids=["No name", "Set particular name"])
    @pytest.mark.smoke
    def test_container_creation(self, default_wallet: WalletInfo, name: str):
        wallet = default_wallet

        placement_rule = "REP 2 IN X CBF 1 SELECT 2 FROM * AS X"
        cid = create_container(
            wallet,
            rule=placement_rule,
            name=name,
            shell=self.shell,
            endpoint=self.cluster.default_rpc_endpoint,
        )

        containers = list_containers(wallet, shell=self.shell, endpoint=self.cluster.default_rpc_endpoint)
        assert cid in containers, f"Expected container {cid} in containers: {containers}"

        container_info: str = get_container(
            wallet,
            cid,
            json_mode=False,
            shell=self.shell,
            endpoint=self.cluster.default_rpc_endpoint,
        )
        container_info = container_info.casefold()  # To ignore case when comparing with expected values

        info_to_check = {
            f"basic ACL: {PRIVATE_ACL_F} (private)",
            f"owner ID: {wallet.get_address_from_json(0)}",
            f"CID: {cid}",
        }
        if name:
            info_to_check.add(f"Name={name}")

        with reporter.step("Check container has correct information"):
            expected_policy = placement_rule.casefold()
            actual_policy = placement_policy_from_container(container_info)
            assert actual_policy == expected_policy, f"Expected policy\n{expected_policy} but got policy\n{actual_policy}"

            for info in info_to_check:
                expected_info = info.casefold()
                assert expected_info in container_info, f"Expected {expected_info} in container info:\n{container_info}"

        with reporter.step("Delete container and check it was deleted"):
            delete_container(
                wallet,
                cid,
                shell=self.shell,
                endpoint=self.cluster.default_rpc_endpoint,
                await_mode=True,
            )
            self.tick_epoch()
            wait_for_container_deletion(wallet, cid, shell=self.shell, endpoint=self.cluster.default_rpc_endpoint)

    @allure.title("Parallel container creation and deletion")
    def test_container_creation_deletion_parallel(self, default_wallet: WalletInfo):
        containers_count = 3
        wallet = default_wallet
        placement_rule = "REP 2 IN X CBF 1 SELECT 2 FROM * AS X"
        iteration_count = 10

        for iteration in range(iteration_count):
            cids: list[str] = []
            with reporter.step(f"Create {containers_count} containers"):
                for _ in range(containers_count):
                    cids.append(
                        create_container(
                            wallet,
                            rule=placement_rule,
                            await_mode=False,
                            shell=self.shell,
                            endpoint=self.cluster.default_rpc_endpoint,
                            wait_for_creation=False,
                        )
                    )

            with reporter.step("Wait for containers occur in container list"):
                for cid in cids:
                    wait_for_container_creation(
                        wallet,
                        cid,
                        sleep_interval=containers_count,
                        shell=self.shell,
                        endpoint=self.cluster.default_rpc_endpoint,
                    )

            with reporter.step("Delete containers and check they were deleted"):
                for cid in cids:
                    delete_container(wallet, cid, shell=self.shell, endpoint=self.cluster.default_rpc_endpoint, await_mode=True)
                    containers_list = list_containers(wallet, shell=self.shell, endpoint=self.cluster.default_rpc_endpoint)
                    assert cid not in containers_list, "Container not deleted"