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

from dataclasses import dataclass

from osm_common.dbbase import DbBase
from osm_common.temporal.activities.base import BaseActivity
from osm_common.temporal.states import VnfInstantiationState, VnfState


class ChangeVnfState(BaseActivity):
    """Updates the VNF State in VNFR.

    Collaborators:
        DB Write:           vnfrs

    Raises (retryable):
        DbException: If DB access/update fails, the collection or DB record ID does not exist.

    Activity Lifecycle:
        This activity should complete relatively quickly (less than a
        second). However, it would be reasonable to wait up to 10
        seconds.

        This activity will not report a heartbeat due to its
        short-running nature.

        It is not necessary to implement a back-off strategy for this
        activity, the operation is idempotent.

    """

    @dataclass
    class Input:
        """
        Input dataclass for changing VNF State.

        Attributes:
        -----------
        vnfr_uuid : str
            The UUID of the VNF which is stored in the OSM vnfrs
            collection in Mongo.

        state : VnfState
            A representation of the VNF state (STOPPED or STARTED).
        """

        vnfr_uuid: str
        state: VnfState

    def __init__(self, db: DbBase):
        super().__init__()
        self.db: DbBase = db

    async def __call__(self, activity_input: Input) -> None:
        raise NotImplementedError()


class ChangeVnfInstantiationState(BaseActivity):
    """Updates the VNF Instantiation State in VNFR.

    Collaborators:
        DB Write:           vnfrs

    Raises (retryable):
        DbException: If DB access or update fails, the collection or DB record ID does not exist.

    Activity Lifecycle:
        This activity should complete relatively quickly (less than a
        second). However, it would be reasonable to wait up to 10
        seconds.

        This activity will not report a heartbeat due to its
        short-running nature.

        It is not necessary to implement a back-off strategy for this
        activity, the operation is idempotent.

    """

    @dataclass
    class Input:
        """
        Input dataclass for changing VNF Instantiation State.

        Attributes:
        -----------
        vnfr_uuid : str
            The UUID of the VNF which is stored in the OSM vnfrs
            collection in Mongo.

        state : VnfInstantiationState
            A representation of the VNF instantiation state (NOT_INSTANTIATED or INSTANTIATED).

        """

        vnfr_uuid: str
        state: VnfInstantiationState

    def __init__(self, db: DbBase):
        super().__init__()
        self.db: DbBase = db

    async def __call__(self, activity_input: Input) -> None:
        raise NotImplementedError()


class GetVnfRecord(BaseActivity):
    """Gets the VNF record and VNF descriptor from Database.

    Collaborators:
        DB read:           vnfrs

    Raises (retryable):
        DbException: If DB read operations fail, the collection or DB record ID does not exist.

    Activity Lifecycle:
        This activity should complete relatively quickly (less than 10
        second).

        This activity will not report a heartbeat due to its
        short-running nature.

        This is an idempotent activity.

    """

    @dataclass
    class Input:
        """
        Input dataclass for get vnf details activity.

        Attributes:
        -----------
        vnfr_uuid : str
            The UUID of the VNF which is stored in the OSM vnfrs
            collection in Mongo.
        """

        vnfr_uuid: str

    @dataclass
    class Output:
        """
        Output dataclass for get vnf details activity.

        Attributes:
        -----------
        vnfr: dict
            The VNF record
        """

        vnfr: dict

    def __init__(self, db: DbBase):
        super().__init__()
        self.db: DbBase = db

    async def __call__(self, activity_input: Input) -> Output:
        raise NotImplementedError()


class GetVnfDescriptor(BaseActivity):
    """Gets the VNF record and VNF descriptor from Database.

    Collaborators:
        DB read:           vnfrs

    Raises (retryable):
        DbException: If DB read operations fail, the collection or DB record ID does not exist.

    Activity Lifecycle:
        This activity should complete relatively quickly (less than 10
        second).

        This activity will not report a heartbeat due to its
        short-running nature.

        This is an idempotent activity.

    """

    @dataclass
    class Input:
        """
        Input dataclass for get vnf descriptor activity.

        Attributes:
        -----------
        vnfd_uuid : str
            The UUID of the VNF descriptor which is stored in the OSM vnfds
            collection in Mongo.
        """

        vnfd_uuid: str

    @dataclass
    class Output:
        """
        Output dataclass for get vnf details activity.

        Attributes:
        -----------
        vnfd : dict
            VNF descriptor retrieved from Database.
        """

        vnfd: dict

    def __init__(self, db: DbBase):
        super().__init__()
        self.db: DbBase = db

    async def __call__(self, activity_input: Input) -> Output:
        raise NotImplementedError()


class SendNotificationForVnf(BaseActivity):
    """Perform Notification operations."""

    @dataclass
    class Input:
        """
        Input dataclass for sending notifications for change in VNF Instantiation State.

        Attributes:
        -----------
        vnfr_uuid : str
            The UUID of the VNF which is stored in the OSM vnfrs
            collection in Mongo.

        state : VnfInstantiationState
            A representation of the VNF instantiation state (NOT_INSTANTIATED or INSTANTIATED).

        """

        vnfr_uuid: str
        state: VnfState

    async def __call__(self, activity_input: Input):
        raise NotImplementedError()


class GetTaskQueue(BaseActivity):
    """Finds the appropriate task queue according to VIM type of VNF.

    Collaborators:
        DB read:           vim_accounts, vnfrs

    Raises (retryable):
        DbException: If DB read operations fail, the collection or DB record ID does not exist.

    Activity Lifecycle:
        This activity should complete relatively quickly (less than a
        second). However, it would be reasonable to wait up to 10
        seconds.

        This activity will not report a heartbeat due to its
        short-running nature.

        It is not necessary to implement a back-off strategy for this
        activity, the operation is idempotent.

    """

    @dataclass
    class Input:
        """
        Input dataclass for get task queue activity.

        Attributes:
        -----------
        vnfr_uuid : str
            The UUID of the VNF which is stored in the OSM vnfrs
            collection in Mongo.

        """

        vnfr_uuid: str

    @dataclass
    class Output:
        """
        Output dataclass for get task queue activity.

        Attributes:
        -----------
        task_queue : str
            Name of the queue which is used to Deploy VNF.
        """

        task_queue: str

    def __init__(self, db: DbBase):
        super().__init__()
        self.db: DbBase = db

    async def __call__(self, activity_input: Input) -> Output:
        raise NotImplementedError()


class GetVimCloud(BaseActivity):
    """Finds the cloud by checking the VIM account of VNF.

    Collaborators:
        DB Read:  vnfrs, vim_accounts

    Raises (retryable):
        DbException: If DB read operations fail, the collection or DB record ID does not exist.

    Activity Lifecycle:
        This activity should complete relatively quickly (less than a
        second). However, it would be reasonable to wait up to 10
        seconds.

        This activity will not report a heartbeat due to its
        short-running nature.

        It is not necessary to implement a back-off strategy for this
        activity, the operation is idempotent.

    """

    @dataclass
    class Input:
        """
        Input dataclass for get vim cloud activity.

        Attributes:
        -----------
        vnfr_uuid : str
            The UUID of the VNF which is stored in the OSM vnfrs
            collection in Mongo.

        """

        vnfr_uuid: str

    @dataclass
    class Output:
        """
        Output dataclass for get vim cloud activity.

        Attributes:
        -----------
        cloud : str
            Type of the cloud which is used to Deploy VNF.
        """

        cloud: str

    def __init__(self, db: DbBase):
        super().__init__()
        self.db: DbBase = db

    async def __call__(self, activity_input: Input) -> Output:
        raise NotImplementedError()


class SetVnfModel(BaseActivity):
    """Updates the model name of VNF in VNFR.

    Collaborators:
        DB Write:           vnfrs

    Raises (retryable):
        DbException: If DB access or update fails, the collection or DB record ID does not exist.

    Activity Lifecycle:
        This activity should complete relatively quickly (less than a
        second). However, it would be reasonable to wait up to 10
        seconds.

        This activity will not report a heartbeat due to its
        short-running nature.

        It is not necessary to implement a back-off strategy for this
        activity, the operation is idempotent.

    """

    @dataclass
    class Input:
        """
        Input dataclass for workflow that instantiates a VNF.

        Attributes:
        -----------
        vnfr_uuid : str
            The UUID of the VNF which is stored in the OSM vnfrs
            collection in Mongo.

        model_name: str

        """

        vnfr_uuid: str
        model_name: str

    def __init__(self, db: DbBase):
        super().__init__()
        self.db: DbBase = db

    async def __call__(self, activity_input: Input) -> None:
        raise NotImplementedError()


class GetModelNames(BaseActivity):
    """Gets the models of VNFs associated with the NS.

    Collaborators:
        DB read:           vnfrs

    Raises (retryable):
        DbException: If DB read operations fail

    Activity Lifecycle:
        This activity should complete relatively quickly (less than a second).

        This activity will not report a heartbeat due to its
        short-running nature.

        This is an idempotent activity.
    """

    @dataclass
    class Input:
        """
        Attributes:
        -----------
        ns_uuid : str
            The UUID of the NS from which we are looking for the model names.
        """

        ns_uuid: str

    @dataclass
    class Output:
        """
        Attributes:
        -----------
        model_names: set[str]
            The set of model names associated with the NS.
        """

        model_names: set[str]

    def __init__(self, db: DbBase):
        super().__init__()
        self.db: DbBase = db

    async def __call__(self, activity_input: Input) -> Output:
        raise NotImplementedError()


class DeleteVnfRecord(BaseActivity):
    """Delete a VNF record from DB.

    Collaborators:
        DB Write:           vnfrs

    Raises (retryable):
        DbException: If DB access fails, the collection does not exist.

    Activity Lifecycle:
        This activity should complete relatively quickly (less than a
        second). However, it would be reasonable to wait up to 10
        seconds.

        This activity will not report a heartbeat due to its
        short-running nature.

        This operation is idempotent.

    """

    @dataclass
    class Input:
        """
        Input dataclass for activity that deletes a VNF record.

        Attributes:
        -----------
        vnfr_uuid : str
            The UUID of the VNF to be deleted from the vnfrs
            collection in Mongo.
        """

        vnfr_uuid: str

    def __init__(self, db: DbBase):
        super().__init__()
        self.db: DbBase = db

    async def __call__(self, activity_input: Input) -> None:
        raise NotImplementedError()
