#######################################################################################
# Copyright ETSI Contributors and Others.
#
# 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.

import asynctest

from osm_common.dataclasses.temporal_dataclasses import (
    CharmInfo,
    VduInstantiateInput,
    VduComputeConstraints,
)
from osm_common.temporal_constants import (
    ACTIVITY_DEPLOY_CHARM,
    ACTIVITY_CHECK_CHARM_STATUS,
    LCM_TASK_QUEUE,
)
from osm_lcm.temporal.vdu_workflows import CheckCharmStatusInput, VduInstantiateWorkflow
from temporalio import activity
from temporalio.client import WorkflowFailureError
from temporalio.testing import WorkflowEnvironment
from temporalio.worker import Worker


@activity.defn(name=ACTIVITY_DEPLOY_CHARM)
async def deploy_charm_mocked(deploy_charm_input: VduInstantiateInput) -> None:
    pass


@activity.defn(name=ACTIVITY_DEPLOY_CHARM)
async def deploy_charm_mocked_raises(deploy_charm_input: VduInstantiateInput) -> None:
    raise Exception()


@activity.defn(name=ACTIVITY_CHECK_CHARM_STATUS)
async def check_charm_status_mocked(check_charm_status: CheckCharmStatusInput) -> None:
    pass


@activity.defn(name=ACTIVITY_CHECK_CHARM_STATUS)
async def check_charm_status_mocked_raises(
    check_charm_status: CheckCharmStatusInput,
) -> None:
    raise Exception()


class TestVduWorkflows(asynctest.TestCase):
    task_queue_name = LCM_TASK_QUEUE
    vim_id = "some-vim-uuid"
    namespace = "some-namespace"
    app_name = "my_app_name"
    channel = "latest"
    entity_url = "ch:my-charm"
    cloud = "microk8s"
    config = {}
    constraints = VduComputeConstraints(mem=1, cores=1)
    charm_info = CharmInfo(app_name, channel, entity_url)
    vdu_instantiate_input = VduInstantiateInput(
        vim_id, namespace, charm_info, constraints, cloud, config
    )
    worflow_id = namespace + "-" + app_name

    async def setUp(self):
        self.env = await WorkflowEnvironment.start_time_skipping()
        self.client = self.env.client

    def get_worker(self, activities: list) -> Worker:
        return Worker(
            self.client,
            task_queue=self.task_queue_name,
            workflows=[VduInstantiateWorkflow],
            activities=activities,
            debug_mode=True,
        )

    async def test_vdu_instantiate(self):
        activities = [deploy_charm_mocked, check_charm_status_mocked]
        async with self.env, self.get_worker(activities):
            result = await self.client.execute_workflow(
                VduInstantiateWorkflow.run,
                arg=self.vdu_instantiate_input,
                id=self.worflow_id,
                task_queue=self.task_queue_name,
            )
            self.assertIsNone(result)

    async def test_vdu_instantiate_deploy_raises(self):
        activities = [deploy_charm_mocked_raises, check_charm_status_mocked]
        async with self.env, self.get_worker(activities):
            with self.assertRaises(WorkflowFailureError):
                result = await self.client.execute_workflow(
                    VduInstantiateWorkflow.run,
                    arg=self.vdu_instantiate_input,
                    id=self.worflow_id,
                    task_queue=self.task_queue_name,
                )
                self.assertIsNone(result)

    async def test_vdu_instantiate_check_status_raises(self):
        activities = [deploy_charm_mocked, check_charm_status_mocked_raises]
        async with self.env, self.get_worker(activities):
            with self.assertRaises(WorkflowFailureError):
                result = await self.client.execute_workflow(
                    VduInstantiateWorkflow.run,
                    arg=self.vdu_instantiate_input,
                    id=self.worflow_id,
                    task_queue=self.task_queue_name,
                )
                self.assertIsNone(result)
