# 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 datetime import datetime
from typing import List, Optional

from dateutil import parser
from gql import gql

from tikka.domains.entities.universal_dividend import UniversalDividend
from tikka.interfaces.adapters.network.connection import NetworkConnectionError
from tikka.interfaces.adapters.network.indexer.universal_dividends import (
    IndexerUniversalDividendsException,
    IndexerUniversalDividendsInterface,
)


class IndexerUniversalDividends(IndexerUniversalDividendsInterface):
    """
    IndexerUniversalDividends class
    """

    def list(
        self,
        address: str,
        limit: int,
        offset: int = 0,
        sort_column: str = IndexerUniversalDividendsInterface.COLUMN_TIMESTAMP,
        sort_order: str = IndexerUniversalDividendsInterface.SORT_ORDER_DESCENDING,
        from_datetime: Optional[datetime] = None,
        to_datetime: Optional[datetime] = None,
    ) -> List[UniversalDividend]:
        __doc__ = (  # pylint: disable=redefined-builtin, unused-variable
            IndexerUniversalDividendsInterface.list.__doc__
        )

        if (
            not self.indexer.connection.is_connected()
            or self.indexer.connection.client is None
        ):
            raise IndexerUniversalDividendsException(NetworkConnectionError())

        # date filter
        date_filter = []
        if from_datetime:
            date_filter.append(
                f'{{ timestamp: {{ greaterThanOrEqualTo: "{from_datetime.isoformat()}" }} }}'
            )
        if to_datetime:
            date_filter.append(
                f'{{ timestamp: {{ lessThanOrEqualTo: "{to_datetime.isoformat()}" }} }}'
            )

        date_filter_str = "and: [" + ", ".join(date_filter) + "]" if date_filter else ""

        # Construct GraphQL request
        query = f"""
            query {{
              identities(
                condition: {{accountId: "{address}"}}
              ) {{
                nodes {{
                  udHistory (
                    first: {limit}
                    offset: {offset}
                    orderBy: {sort_column.upper()}_{sort_order.upper()}
                    filter: {{
                        {date_filter_str}
                    }}
                  ) {{
                    nodes {{
                        id
                        identity {{
                            index
                            name
                        }}
                        amount
                        timestamp
                    }}
                  }}
                }}
              }}
            }}
        """

        # "data": {
        #     "identities": {
        #         "nodes": [
        #             {
        #                 "udHistory": {
        #                     "nodes": [
        #                         {
        #                             "id": "ud-vit-2081567-0002081567-46afb-000000",
        #                             "identity": {
        #                                 "index": 58,
        #                                 "name": "vit"
        #                             },
        #                             "amount": "1180",
        #                             "timestamp": "2026-03-05T01:44:36+00:00"
        #                         },

        try:
            result = self.indexer.connection.client.execute(gql(query))
        except Exception as exception:
            raise IndexerUniversalDividendsException(exception)

        universal_dividends: List[UniversalDividend] = []
        if len(result["identities"]["nodes"]) == 0:
            return universal_dividends

        for universal_dividend in result["identities"]["nodes"][0]["udHistory"][
            "nodes"
        ]:
            universal_dividends.append(
                UniversalDividend(
                    id=universal_dividend["id"],
                    address=address,
                    identity_index=universal_dividend["identity"]["index"],
                    identity_name=universal_dividend["identity"]["name"],
                    amount=universal_dividend["amount"],
                    timestamp=parser.parse(universal_dividend["timestamp"]),
                )
            )

        return universal_dividends

    def count(self, address) -> int:
        __doc__ = (  # pylint: disable=redefined-builtin, unused-variable
            IndexerUniversalDividendsInterface.count.__doc__
        )
        if (
            not self.indexer.connection.is_connected()
            or self.indexer.connection.client is None
        ):
            raise IndexerUniversalDividendsException(NetworkConnectionError())

        query = f"""
        query {{
            identities(
                condition: {{accountId: "{address}"}}
            )                 
            nodes {{
                  udHistory {{
                    totalCount
                  }}
            }}
        }}
        """
        try:
            result = self.indexer.connection.client.execute(gql(query))
        except Exception as exception:
            raise IndexerUniversalDividendsException(exception)

        # {
        #     "data": {
        #         "identities": {
        #             "nodes": [
        #                 {
        #                     "udHistory": {
        #                         "totalCount": 145
        #                     }
        #                 }
        #             ]
        #         }
        #     }
        # }
        return result["identities"]["nodes"]["udHistory"]["totalCount"]
