# Copyright 2021 Vincent Texier <vit@free.fr>
#
# This software is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
from typing import Any, Dict, List, Optional

from tikka.domains.entities.identity import Certification
from tikka.domains.events import EventDispatcher
from tikka.interfaces.adapters.network.indexer.certifications import (
    IndexerCertificationsInterface,
)
from tikka.interfaces.adapters.repository.certifications import (
    CertificationsRepositoryInterface,
)


class Certifications:
    """
    Certifications domain class
    """

    def __init__(
        self,
        repository: CertificationsRepositoryInterface,
        indexer_certifications: IndexerCertificationsInterface,
        event_dispatcher: EventDispatcher,
    ):
        """
        Init Certifications domain

        :param repository: TransfersRepositoryInterface adapter instance
        :param indexer_certifications: NodeTransfersInterface adapter instance
        :param event_dispatcher: EventDispatcher instance
        """
        self.repository = repository
        self.indexer_certifications = indexer_certifications
        self.event_dispatcher = event_dispatcher

    def set_list(
        self, identity_index: int, certifications: List[Certification]
    ) -> None:
        """
        Set identity certification list in repository

        :param identity_index: Identity index
        :param certifications: List of Certification instances
        :return:
        """
        self.repository.set_list(identity_index, certifications)

    def list(
        self,
        identity_index: int,
        filters: Optional[Dict[str, Any]] = None,
        sort_column: str = CertificationsRepositoryInterface.COLUMN_EXPIRE_ON,
        sort_order: str = CertificationsRepositoryInterface.SORT_ORDER_ASCENDING,
        limit: int = 10,
        offset: int = 0,
    ) -> List[Certification]:
        """
        List certifications from and to identity_index, from repository with optional filters and sort_column

        :param identity_index: Identity_index
        :param filters: Dict with {column: value} filters or None
        :param sort_column: Sort column constant, TransfersRepositoryInterface.COLUMN_TIMESTAMP by default
        :param sort_order: Sort order constant, TransfersRepositoryInterface.SORT_ORDER_DESCENDING by default
        :param limit: Number of rows to return
        :param offset: Offset of first row to return
        :return:
        """
        return self.repository.list(
            identity_index, filters, sort_column, sort_order, limit, offset
        )

    def delete_by_address(self, address: str, exclude: List[str]) -> None:
        """
        Delete certification history issued from or received by address
        (exclude certifications with address in exclude list)

        :param address: Account address of certifications to delete
        :param exclude: List of address to not delete
        :return:
        """
        self.repository.delete_by_address(address, exclude)

    def delete_all(self) -> None:
        """
        Delete all certifications in repository

        :return:
        """
        self.repository.delete_all()

    def network_fetch_certifications_for_identity(self, identity_index: int) -> None:
        """
        Fetch certifications from and to identity_index

        :param identity_index: Identity index
        :return:
        """
        certifications = self.indexer_certifications.list(identity_index, 1000, 0)
        self.set_list(identity_index, certifications)

    def count(self, identity_index: int) -> int:
        """
        Return count of certifications issued by identity_index

        :param identity_index: Identity index
        :return:
        """
        return len(self.list(identity_index))

    def count_received(self, identity_index: int) -> int:
        """
        Return count of certifications received by identity_index

        :param identity_index: Identity index
        :return:
        """
        return len(
            self.list(
                identity_index,
                filters={
                    CertificationsRepositoryInterface.COLUMN_RECEIVER_IDENTITY_INDEX: identity_index
                },
            )
        )
