"""
Strategies from Axelrod's second tournament. All strategies in this module are
prefixed by `SecondBy` to indicate that they were submitted in Axelrod's Second
tournament by the given author.
"""

from typing import List

import numpy as np

from axelrod.action import Action

from axelrod.interaction_utils import compute_final_score

from axelrod.player import Player

from axelrod.strategies.finite_state_machines import FSMPlayer

C, D = Action.C, Action.D

class FSMPlayer(Player):
    """Abstract base class for finite state machine players."""

    name = "FSM Player"

    classifier: Dict[Text, Any] = {
        "memory_depth": 1,
        "stochastic": False,
        "long_run_time": False,
        "inspects_source": False,
        "manipulates_source": False,
        "manipulates_state": False,
    }

    def __init__(
        self,
        transitions: Tuple[Transition, ...] = ((1, C, 1, C), (1, D, 1, D)),
        initial_state: int = 1,
        initial_action: Action = C,
    ) -> None:
        Player.__init__(self)
        self.initial_state = initial_state
        self.initial_action = initial_action
        self.fsm = SimpleFSM(transitions, initial_state)

    def strategy(self, opponent: Player) -> Action:
        """Actual strategy definition that determines player's action."""
        if len(self.history) == 0:
            return self.initial_action
        else:
            return self.fsm.move(opponent.history[-1])

class SecondByMikkelson(FSMPlayer):
    """
    Strategy submitted to Axelrod's second tournament by Ray Mikkelson (K66R)
    and came in twentieth in that tournament.

    The strategy keeps track of a variable called `credit`, which determines if
    the strategy will Cooperate, in the sense that if `credit` is positive,
    then the strategy Cooperates.  `credit` is initialized to 7.  After the
    first turn, `credit` increments if the opponent Cooperated last turn, and
    decreases by two otherwise.  `credit` is capped above by 8 and below by -7.
    [`credit` is assessed as postive or negative, after increasing based on
    opponent's last turn.]

    If `credit` is non-positive within the first ten turns, then the strategy
    Defects and `credit` is set to 4.  If `credit` is non-positive later, then
    the strategy Defects if and only if (total # opponent Defections) / (turn#)
    is at least 15%.  [Turn # starts at 1.]

    Names:

    - Mikkelson: [Axelrod1980b]_
    """

    name = "Second by Mikkelson"
    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.credit = 7

    def strategy(self, opponent: Player) -> Action:
        turn = len(self.history) + 1
        if turn == 1:
            return C

        if opponent.history[-1] == C:
            self.credit += 1
            if self.credit > 8:
                self.credit = 8
        else:
            self.credit -= 2
            if self.credit < -7:
                self.credit = -7

        if turn == 2:
            return C
        if self.credit > 0:
            return C
        if turn <= 10:
            self.credit = 4
            return D
        if opponent.defections / turn >= 0.15:
            return D
        return C