"""
Strategies submitted to Axelrod's first tournament. All strategies in this
module are prefixed by `FirstBy` to indicate that they were submitted in
Axelrod's First tournament by the given author.

Note that these strategies are implemented from the descriptions presented
in:

Axelrod, R. (1980). Effective Choice in the Prisoner’s Dilemma.
Journal of Conflict Resolution, 24(1), 3–25.

These descriptions are not always clear and/or precise and when assumptions have
been made they are explained in the strategy docstrings.
"""

from typing import Dict, List, Optional, Tuple

from scipy.stats import chisquare

from axelrod.action import Action

from axelrod.player import Player

from axelrod.strategy_transformers import FinalTransformer

from .memoryone import MemoryOnePlayer

C, D = Action.C, Action.D

class FirstByShubik(Player):
    """
    Submitted to Axelrod's first tournament by Martin Shubik.

    The description written in [Axelrod1980]_ is:

    > "This rule cooperates until the other defects, and then defects once. If
    > the other defects again after the rule's cooperation is resumed, the rule
    > defects twice. In general, the length of retaliation is increased by one for
    > each departure from mutual cooperation. This rule is described with its
    > strategic implications in Shubik (1970). Further treatment of its is given
    > in Taylor (1976).

    There is some room for interpretation as to how the strategy reacts to a
    defection on the turn where it starts to cooperate once more. In Shubik
    (1970) the strategy is described as:

    > "I will play my move 1 to begin with and will continue to do so, so long
    > as my information shows that the other player has chosen his move 1. If my
    > information tells me he has used move 2, then I will use move 2 for the
    > immediate k subsequent periods, after which I will resume using move 1. If
    > he uses his move 2 again after I have resumed using move 1, then I will
    > switch to move 2 for the k + 1 immediately subsequent periods . . . and so
    > on, increasing my retaliation by an extra period for each departure from the
    > (1, 1) steady state."

    This is interpreted as:

    The player cooperates, if when it is cooperating, the opponent defects it
    defects for k rounds. After k rounds it starts cooperating again and
    increments the value of k if the opponent defects again.

    This strategy came 5th in Axelrod's original tournament.

    Names:

    - Shubik: [Axelrod1980]_
    """

    name = "First by Shubik"
    classifier = {
        "memory_depth": float("inf"),
        "stochastic": False,
        "long_run_time": False,
        "inspects_source": False,
        "manipulates_source": False,
        "manipulates_state": False,
    }

    def __init__(self) -> None:
        super().__init__()
        self.is_retaliating = False
        self.retaliation_length = 0
        self.retaliation_remaining = 0

    def _decrease_retaliation_counter(self):
        """Lower the remaining owed retaliation count and flip to non-retaliate
        if the count drops to zero."""
        if self.is_retaliating:
            self.retaliation_remaining -= 1
            if self.retaliation_remaining == 0:
                self.is_retaliating = False

    def strategy(self, opponent: Player) -> Action:
        """Actual strategy definition that determines player's action."""
        if not opponent.history:
            return C

        if self.is_retaliating:
            # Are we retaliating still?
            self._decrease_retaliation_counter()
            return D

        if opponent.history[-1] == D and self.history[-1] == C:
            # "If he uses his move 2 again after I have resumed using move 1,
            # then I will switch to move 2 for the k + 1 immediately subsequent
            # periods"
            self.is_retaliating = True
            self.retaliation_length += 1
            self.retaliation_remaining = self.retaliation_length
            self._decrease_retaliation_counter()
            return D
        return C