import time
from typing import List, Tuple

import pyautogui
import shenzhen_solitaire.board as board
import shenzhen_solitaire.card_detection.adjustment as adjustment
import shenzhen_solitaire.card_detection.configuration as configuration
import shenzhen_solitaire.solver.board_actions as board_actions
import warnings


def drag(
    src: Tuple[int, int], dst: Tuple[int, int], offset: Tuple[int, int] = (0, 0)
) -> None:

    pyautogui.moveTo(x=src[0] + offset[0], y=src[1] + offset[1])
    pyautogui.dragTo(
        x=dst[0] + offset[0],
        y=dst[1] + offset[1],
        duration=0.4,
        tween=lambda x: 0 if x < 0.5 else 1,
    )


def dragSquare(
    src: Tuple[int, int, int, int],
    dst: Tuple[int, int, int, int],
    offset: Tuple[int, int] = (0, 0),
) -> None:
    drag(
        (src[0] + (src[2] - src[0]) // 2, src[1] + (src[3] - src[1]) // 2),
        (dst[0] + (dst[2] - dst[0]) // 2, dst[1] + (dst[3] - dst[1]) // 2),
        offset,
    )


def click(point: Tuple[int, int], offset: Tuple[int, int] = (0, 0)) -> None:
    pyautogui.moveTo(x=point[0] + offset[0], y=point[1] + offset[1])
    pyautogui.mouseDown()
    time.sleep(0.2)
    pyautogui.mouseUp()


def clickSquare(
    field: Tuple[int, int, int, int], offset: Tuple[int, int] = (0, 0)
) -> None:
    click(
        (field[0] + (field[2] - field[0]) // 2, field[1] + (field[3] - field[1]) // 2),
        offset,
    )


def handle_action(
    action: board_actions.Action,
    offset: Tuple[int, int],
    conf: configuration.Configuration,
) -> None:
    if isinstance(action, board_actions.MoveAction):
        src = adjustment.get_square(
            conf.field_adjustment,
            index_x=action.source_id,
            index_y=action.source_row_index,
        )
        dst = adjustment.get_square(
            conf.field_adjustment,
            index_x=action.destination_id,
            index_y=action.destination_row_index,
        )
        dragSquare(src, dst, offset)
        return
    if isinstance(action, board_actions.HuaKillAction):
        warnings.warn("Hua kill should be handled before handle_action")
        return
    if isinstance(action, board_actions.BunkerizeAction):
        field = adjustment.get_square(
            conf.field_adjustment,
            index_x=action.field_id,
            index_y=action.field_row_index,
        )
        bunker = adjustment.get_square(
            conf.bunker_adjustment, index_x=action.bunker_id, index_y=0,
        )
        if action.to_bunker:
            dragSquare(field, bunker, offset)
        else:
            dragSquare(bunker, field, offset)
        return
    if isinstance(action, board_actions.DragonKillAction):
        dragon_sequence = [
            board.SpecialCard.Zhong,
            board.SpecialCard.Fa,
            board.SpecialCard.Bai,
        ]
        field = adjustment.get_square(
            conf.special_button_adjustment,
            index_x=0,
            index_y=dragon_sequence.index(action.dragon),
        )
        clickSquare(
            field, offset,
        )
        time.sleep(1)
        return
    if isinstance(action, board_actions.GoalAction):
        dst = adjustment.get_square(
            conf.goal_adjustment, index_x=action.goal_id, index_y=0,
        )
        if action.source_position == board.Position.Field:
            assert action.source_row_index is not None
            src = adjustment.get_square(
                conf.field_adjustment,
                index_x=action.source_id,
                index_y=action.source_row_index,
            )
        else:
            assert action.source_position == board.Position.Bunker
            src = adjustment.get_square(
                conf.bunker_adjustment, index_x=action.source_id, index_y=0,
            )
        dragSquare(src, dst, offset)
        return
    raise AssertionError("You forgot an Action type")


def handle_actions(
    actions: List[board_actions.Action],
    offset: Tuple[int, int],
    conf: configuration.Configuration,
) -> None:
    automatic_count = 0
    for action in actions:
        print(action)
        if isinstance(action, board_actions.HuaKillAction):
            automatic_count += 1
        else:
            time.sleep(0.5 * automatic_count)
            automatic_count = 0
            handle_action(action, offset, conf)
    time.sleep(0.5 * automatic_count)
