# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
#   Copyright 2018-2019 Fetch.AI Limited
#
#   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.
#
# ------------------------------------------------------------------------------

"""This module contains the strategy class."""

import datetime
from typing import Dict, List, Optional, Tuple, cast

from packages.fetchai.skills.confirmation_aw2.registration_db import RegistrationDB
from packages.fetchai.skills.generic_buyer.strategy import GenericStrategy


class Strategy(GenericStrategy):
    """Strategy class extending Generic Strategy."""

    def __init__(self, **kwargs) -> None:
        """
        Initialize the strategy of the agent.

        :return: None
        """
        aw1_aea: Optional[str] = kwargs.pop("aw1_aea", None)
        if aw1_aea is None:
            raise ValueError("aw1_aea must be provided!")
        self.aw1_aea = aw1_aea
        self.mininum_hours_between_txs = kwargs.pop("mininum_hours_between_txs", 4)
        self.minimum_minutes_since_last_attempt = kwargs.pop(
            "minimum_minutes_since_last_attempt", 2
        )
        super().__init__(**kwargs)
        self.last_attempt: Dict[str, datetime.datetime] = {}

    def get_acceptable_counterparties(
        self, counterparties: Tuple[str, ...]
    ) -> Tuple[str, ...]:
        """
        Process counterparties and drop unacceptable ones.

        :return: list of counterparties
        """
        valid_counterparties: List[str] = []
        for counterparty in counterparties:
            if self.is_valid_counterparty(counterparty):
                valid_counterparties.append(counterparty)
        return tuple(valid_counterparties)

    def is_enough_time_since_last_attempt(self, counterparty: str) -> bool:
        """
        Check if enough time has passed since last attempt for potential previous trade to complete.

        :return: bool indicating validity
        """
        last_time = self.last_attempt.get(counterparty, None)
        if last_time is None:
            return True
        result = datetime.datetime.now() > last_time + datetime.timedelta(
            minutes=self.minimum_minutes_since_last_attempt
        )
        return result

    def is_valid_counterparty(self, counterparty: str) -> bool:
        """
        Check if the counterparty is valid.

        :return: bool indicating validity
        """
        registration_db = cast(RegistrationDB, self.context.registration_db)
        if not registration_db.is_registered(counterparty):
            self.context.logger.info(
                f"Invalid counterparty={counterparty}, not registered!"
            )
            return False
        if not self.is_enough_time_since_last_attempt(counterparty):
            self.context.logger.debug(
                f"Not enough time since last attempt for counterparty={counterparty}!"
            )
            return False
        self.last_attempt[counterparty] = datetime.datetime.now()
        if not registration_db.is_allowed_to_trade(
            counterparty, self.mininum_hours_between_txs
        ):
            return False
        return True

    def successful_trade_with_counterparty(
        self, counterparty: str, data: Dict[str, str]
    ) -> None:
        """
        Do something on successful trade.

        :param counterparty: the counterparty address
        :param data: the data
        :return: False
        """
        registration_db = cast(RegistrationDB, self.context.registration_db)
        registration_db.set_trade(counterparty, datetime.datetime.now(), data)
        self.context.logger.info(
            f"Successful trade with={counterparty}. Data acquired={data}!"
        )

    def register_counterparty(self, counterparty: str) -> None:
        """
        Register a counterparty.

        :param counterparty: the counterparty address
        :param data: the data
        :return: False
        """
        registration_db = cast(RegistrationDB, self.context.registration_db)
        registration_db.set_registered(counterparty)
