from typing import Tuple

import matplotlib
from matplotlib.patches import Arc, Wedge, Rectangle

from floodlight.utils.types import Numeric


def plot_handball_pitch(
    xlim: Tuple[Numeric, Numeric],
    ylim: Tuple[Numeric, Numeric],
    unit: str,
    color_scheme: str,
    show_axis_ticks: bool,
    ax: matplotlib.axes,
    **kwargs,
) -> matplotlib.axes:
    """Plots a handball pitch on a given matplotlib.axes.

    Parameters
    ----------
    xlim: Tuple[Numeric, Numeric]
        Limits of pitch boundaries in longitudinal direction. This tuple has the form
        (x_min, x_max) and delimits the length of the pitch (not of any actual data)
        within the coordinate system.
    ylim: Tuple[Numeric, Numeric]
        Limits of pitch boundaries in lateral direction. This tuple has the form
        (y_min, y_max) and delimits the width of the pitch (not of any actual data)
        within the coordinate system.
    unit: str
        The unit in which data is measured along axes. Possible types are
        {'m', 'cm', 'percent'}.
    color_scheme: str
        Color scheme of the plot. One of {'standard', 'bw'}.
    show_axis_ticks: bool
        If set to True, the axis ticks are visible.
    ax: matplotlib.axes
        Axes from matplotlib library on which the handball field is plotted.
    kwargs:
        Optional keyworded arguments {'linewidth', 'zorder', 'scalex', 'scaley'}
        which can be used for the plot functions from matplotlib. The kwargs are
        only passed to all the plot functions of matplotlib.

    Returns
    -------
    axes : matplotlib.axes
        Axes from matplotlib library on which a handball pitch is plotted.
    """

    # kwargs which are used to configure the plot with default values 1 and 0.
    # all the other kwargs will be just passed to all the plot functions.
    linewidth = kwargs.pop("linewidth", 1)
    zorder = kwargs.pop("zorder", 0)

    # customizing visualization
    if color_scheme == "bw":
        ax.set_facecolor("white")  # color of the pitch
        color_contour_lines = "black"
        color_goal_area_fill = "white"
        color_goal_posts = "black"
    else:
        ax.set_facecolor("skyblue")  # color of the pitch
        color_contour_lines = "white"
        color_goal_area_fill = "khaki"
        color_goal_posts = "white"

    # Positions and ranges on the field which are used for plotting all lines and
    # arcs.
    # All the positions and ranges are scaled based on percentages of the x-range
    # and y-range.

    # key positions for the handball pitch
    xmin, xmax = xlim
    ymin, ymax = ylim
    x_range = xmax - xmin
    y_range = ymax - ymin
    x_half = (xmax + xmin) / 2
    y_half = (ymax + ymin) / 2

    # Positions (x,y) on the handball pitch
    pos_left_side_right_goal_post = (xmin, ymin + y_range * 0.425)
    pos_left_side_left_goal_post = (xmin, ymin + y_range * 0.575)
    pos_right_side_left_goal_post = (xmax, ymin + y_range * 0.425)
    pos_right_side_right_goal_post = (xmax, ymin + y_range * 0.575)
    pos_start_right_side_rect_goal_area = (
        xmax - x_range * 0.15,
        ymin + y_range * 0.425,
    )

    # Ranges on the handball pitch
    y_height_free_throw_arc = y_range * 0.9
    x_width_free_throw_arc = x_range * 0.45
    y_height_goal_area_arc = y_range * 0.6
    x_width_goal_area_arc = x_range * 0.3
    radius_goal_area_arc = x_range * 0.15
    width_goal = y_range * 0.15
    x_height_goal = x_range * 0.025

    # Y positions on the handball pitch
    y_range_center_to_post = width_goal / 2
    y_pos_goal_lower_post = y_half - y_range_center_to_post
    y_pos_goal_upper_post = y_half + y_range_center_to_post
    y_pos_lower_goal_posts = ymin + y_range * 0.425
    y_pos_upper_goal_posts = ymin + y_range * 0.575
    lower_y_pos_4m_line = ymin + (y_range * 0.49625)
    upper_y_pos_4m_line = ymin + (y_range * 0.50375)
    lower_y_pos_7m_line = ymin + (y_range * 0.475)
    upper_y_pos_7m_line = ymin + (y_range * 0.525)

    # X positions on the handball pitch
    x_pos_left_side_goal_area_line_edge = xmin + (x_range * 0.15)
    x_pos_right_side_goal_area_line_edge = xmax - (x_range * 0.15)
    x_pos_left_side_free_throw_line_edge = xmin + (x_range * 0.225)
    x_pos_right_side_free_throw_line_edge = xmax - (x_range * 0.225)
    x_pos_left_side_4m_line = xmin + (x_range * 0.1)
    x_pos_right_side_4m_line = xmax - (x_range * 0.1)
    x_pos_left_side_7m_line = xmin + (x_range * 0.175)
    x_pos_right_side_7m_line = xmax - (x_range * 0.175)

    # angle for the free throw arc changes when unit is 'percent'
    angle = 10 if unit == "percent" else 0

    # margins of the plot
    x_margin = x_range * 0.025
    y_margin = y_range * 0.05

    # set up the boundaries of ax
    ax.set_xlim([xmin - (x_height_goal + x_margin), xmax + (x_height_goal + x_margin)])
    ax.set_ylim([ymin - y_margin, ymax + y_margin])

    # paint handball pitch with all properties
    # main boundaries
    ax.plot(
        [xmin, xmin],
        [ymin, ymax],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [xmax, xmax],
        [ymin, ymax],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [xmin, xmax],
        [ymin, ymin],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [xmin, xmax],
        [ymax, ymax],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )

    # midline
    ax.plot(
        [x_half, x_half],
        [ymin, ymax],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
        **kwargs,
    )

    # free-throw lines
    # lower left
    ax.add_patch(
        Arc(
            pos_left_side_right_goal_post,
            width=x_width_free_throw_arc,
            height=y_height_free_throw_arc,
            angle=0,
            theta1=290 - angle,
            theta2=360,
            linestyle="dashed",
            linewidth=linewidth,
            color=color_contour_lines,
            zorder=zorder,
            **kwargs,
        )
    )
    # upper left
    ax.add_patch(
        Arc(
            pos_left_side_left_goal_post,
            width=x_width_free_throw_arc,
            height=y_height_free_throw_arc,
            angle=0,
            theta1=0,
            theta2=70 + angle,
            linestyle="dashed",
            linewidth=linewidth,
            color=color_contour_lines,
            zorder=zorder,
            **kwargs,
        )
    )
    # lower right
    ax.add_patch(
        Arc(
            pos_right_side_left_goal_post,
            width=x_width_free_throw_arc,
            height=y_height_free_throw_arc,
            angle=0,
            theta1=180,
            theta2=250 + angle,
            linestyle="dashed",
            linewidth=linewidth,
            color=color_contour_lines,
            zorder=zorder,
            **kwargs,
        )
    )
    # upper right
    ax.add_patch(
        Arc(
            pos_right_side_right_goal_post,
            width=x_width_free_throw_arc,
            height=y_height_free_throw_arc,
            angle=0,
            theta1=110 - angle,
            theta2=180,
            linestyle="dashed",
            linewidth=linewidth,
            color=color_contour_lines,
            zorder=zorder,
            **kwargs,
        )
    )
    # goal area lines
    # lower left
    # Filling the goal area
    if unit != "percent":  # Since wedges can't be scaled
        ax.add_patch(
            Wedge(
                pos_left_side_right_goal_post,
                r=radius_goal_area_arc,
                theta1=270,
                theta2=360,
                linewidth=linewidth,
                color=color_goal_area_fill,
                zorder=zorder,
                **kwargs,
            )
        )
    # goal area line
    ax.add_patch(
        Arc(
            pos_left_side_right_goal_post,
            height=y_height_goal_area_arc,
            width=x_width_goal_area_arc,
            angle=0,
            theta1=270,
            theta2=360,
            linewidth=linewidth,
            color=color_contour_lines,
            zorder=zorder,
            **kwargs,
        )
    )
    # upper left
    # filling the goal area
    if unit != "percent":  # Since wedges can't be scaled
        ax.add_patch(
            Wedge(
                pos_left_side_left_goal_post,
                r=radius_goal_area_arc,
                theta1=0,
                theta2=90,
                linewidth=linewidth,
                color=color_goal_area_fill,
                zorder=zorder,
                **kwargs,
            )
        )
    # goal area line
    ax.add_patch(
        Arc(
            pos_left_side_left_goal_post,
            height=y_height_goal_area_arc,
            width=x_width_goal_area_arc,
            angle=0,
            theta1=0,
            theta2=90,
            linewidth=linewidth,
            color=color_contour_lines,
            zorder=zorder,
            **kwargs,
        )
    )
    # lower right
    # filling the goal area
    if unit != "percent":  # Since wedges can't be scaled
        ax.add_patch(
            Wedge(
                pos_right_side_left_goal_post,
                r=radius_goal_area_arc,
                theta1=180,
                theta2=270,
                linewidth=linewidth,
                color=color_goal_area_fill,
                zorder=zorder,
                **kwargs,
            )
        )
    # goal area line
    ax.add_patch(
        Arc(
            pos_right_side_left_goal_post,
            height=y_height_goal_area_arc,
            width=x_width_goal_area_arc,
            angle=0,
            theta1=180,
            theta2=270,
            linewidth=linewidth,
            color=color_contour_lines,
            zorder=zorder,
            **kwargs,
        )
    )
    # upper right
    # filling the goal area
    if unit != "percent":  # Since wedges can't be scaled
        ax.add_patch(
            Wedge(
                pos_right_side_right_goal_post,
                r=radius_goal_area_arc,
                theta1=90,
                theta2=180,
                linewidth=linewidth,
                color=color_goal_area_fill,
                zorder=zorder,
                **kwargs,
            )
        )
    # goal area line
    ax.add_patch(
        Arc(
            pos_right_side_right_goal_post,
            height=y_height_goal_area_arc,
            width=x_width_goal_area_arc,
            angle=0,
            theta1=90,
            theta2=180,
            linewidth=linewidth,
            color=color_contour_lines,
            zorder=zorder,
            **kwargs,
        )
    )
    # mid left
    # filling the goal area
    if unit != "percent":  # Since wedges can't be scaled the rectangles
        ax.add_patch(  # are also not used to fill the goal area
            Rectangle(
                pos_left_side_right_goal_post,
                width=radius_goal_area_arc,
                height=width_goal,
                color=color_goal_area_fill,
                zorder=zorder,
                **kwargs,
            )
        )
    # mid right
    # filling the goal area
    if unit != "percent":  # Since wedges can't be scaled the rectangles
        ax.add_patch(  # are also not used to fill the goal area
            Rectangle(
                pos_start_right_side_rect_goal_area,
                width=radius_goal_area_arc,
                height=width_goal,
                color=color_goal_area_fill,
                zorder=zorder,
                **kwargs,
            )
        )

    # vertical goal area lines
    ax.plot(
        [x_pos_left_side_goal_area_line_edge, x_pos_left_side_goal_area_line_edge],
        [y_pos_lower_goal_posts, y_pos_upper_goal_posts],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [
            x_pos_right_side_goal_area_line_edge,
            x_pos_right_side_goal_area_line_edge,
        ],
        [y_pos_lower_goal_posts, y_pos_upper_goal_posts],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    # vertical free throw lines
    ax.plot(
        [
            x_pos_left_side_free_throw_line_edge,
            x_pos_left_side_free_throw_line_edge,
        ],
        [y_pos_lower_goal_posts, y_pos_upper_goal_posts],
        color=color_contour_lines,
        linewidth=linewidth,
        linestyle="dashed",
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [
            x_pos_right_side_free_throw_line_edge,
            x_pos_right_side_free_throw_line_edge,
        ],
        [y_pos_lower_goal_posts, y_pos_upper_goal_posts],
        color=color_contour_lines,
        linewidth=linewidth,
        linestyle="dashed",
        zorder=zorder,
        **kwargs,
    )

    # 4 m lines
    ax.plot(
        [x_pos_left_side_4m_line, x_pos_left_side_4m_line],
        [lower_y_pos_4m_line, upper_y_pos_4m_line],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [x_pos_right_side_4m_line, x_pos_right_side_4m_line],
        [lower_y_pos_4m_line, upper_y_pos_4m_line],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )

    # 7 m lines
    ax.plot(
        [x_pos_left_side_7m_line, x_pos_left_side_7m_line],
        [lower_y_pos_7m_line, upper_y_pos_7m_line],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [x_pos_right_side_7m_line, x_pos_right_side_7m_line],
        [lower_y_pos_7m_line, upper_y_pos_7m_line],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )

    # goals
    # left goal
    ax.plot(
        [xmin - x_height_goal, xmin - x_height_goal],
        [y_pos_goal_lower_post, y_pos_goal_upper_post],
        color=color_goal_posts,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [xmin - x_height_goal, xmin],
        [y_pos_goal_lower_post, y_pos_goal_lower_post],
        color=color_goal_posts,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [xmin - x_height_goal, xmin],
        [y_pos_goal_upper_post, y_pos_goal_upper_post],
        color=color_goal_posts,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    # right goal
    ax.plot(
        [xmax + x_height_goal, xmax + x_height_goal],
        [y_pos_goal_lower_post, y_pos_goal_upper_post],
        color=color_goal_posts,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [xmax + x_height_goal, xmax],
        [y_pos_goal_lower_post, y_pos_goal_lower_post],
        color=color_goal_posts,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    ax.plot(
        [xmax + x_height_goal, xmax],
        [y_pos_goal_upper_post, y_pos_goal_upper_post],
        color=color_goal_posts,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    # baseline
    ax.plot(
        [xmax, xmax],
        [ymin, ymax],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )
    # baseline
    ax.plot(
        [xmin, xmin],
        [ymin, ymax],
        color=color_contour_lines,
        linewidth=linewidth,
        zorder=zorder,
        **kwargs,
    )

    # remove labels and ticks
    if not show_axis_ticks:
        ax.xaxis.set_major_locator(matplotlib.ticker.NullLocator())
        ax.yaxis.set_major_locator(matplotlib.ticker.NullLocator())

    return ax


def plot_football_pitch(
    xlim: Tuple[Numeric, Numeric],
    ylim: Tuple[Numeric, Numeric],
    length: Numeric,
    width: Numeric,
    unit: str,
    color_scheme: str,
    show_axis_ticks: bool,
    ax: matplotlib.axes,
    **kwargs,
) -> matplotlib.axes:
    """Plots a football pitch on a given matplotlib.axes.

    Parameters
    ----------
    xlim: Tuple[Numeric, Numeric]
        Limits of pitch boundaries in longitudinal direction. This tuple has the form
        (x_min, x_max) and delimits the length of the pitch (not of any actual data)
        within the coordinate system.
    ylim: Tuple[Numeric, Numeric]
        Limits of pitch boundaries in lateral direction. This tuple has the form
        (y_min, y_max) and delimits the width of the pitch (not of any actual data)
        within the coordinate system.
    length: Numeric
        Length of the actual pitch in `unit`.
    width: Numeric, optional
        Width of the actual pitch in `unit`.
    unit: str
        The unit in which data is measured along axes. Possible types are
        {'m', 'cm', 'percent'}.
    color_scheme: str
        Color scheme of the plot. One of {'standard', 'bw'}.
    show_axis_ticks: bool
        If set to True, the axis ticks are visible.
    ax: matplotlib.axes
        Axes from matplotlib library on which the football field is plotted.
    kwargs:
        Optional keyworded arguments {'linewidth', 'zorder', 'scalex', 'scaley'}
        which can be used for the plot functions from matplotlib. The kwargs are
        only passed to all the plot functions of matplotlib.

    Returns
    -------
    axes : matplotlib.axes
        Axes from matplotlib library on which a football pitch is plotted.
    """
    # kwargs which are used to configure the plot with default values 1 and 0.
    # all the other kwargs will be just passed to all the plot functions.
    linewidth = kwargs.pop("linewidth", 1)
    zorder = kwargs.pop("zorder", 0)

    # customizing visualization
    if color_scheme == "bw":
        ax.set_facecolor("white")  # color of the pitch
        color_contour_lines = "black"
    else:
        ax.set_facecolor("green")  # color of the pitch
        color_contour_lines = "white"

    # Since football pitch sizes can vary while the elements on the pitch
    # (i.e penalty area) have the same size, the actual elements on the pitch can't
    # be scaled based on the x- or y-range.
    # Therefore a norm factor for the x and y direction is needed for every element
    # on the pitch that has a fixed size.
    # The norm factor is specified based on the given unit.
    # If the unit is 'm' or 'cm' the ratio between x and y is set to 1
    # (see in the Pitch.plot() method ax.set_aspect(1)) and the norm factos are set
    # to 1 ('m') or 100 ('cm'). But if the unit is 'percent' the ratio between
    # width/length is set to ax.set_aspect(width/length).
    # That means if an element like the goal area, is drawn, it get's rescaled based
    # on the ratio of width and length.

    # norm_factor for all elements on the pitch that are scaled in the x direction
    norm_factor_x = (
        1
        if unit == "m"
        else 100
        if unit == "cm"
        else 100 / length
        if length
        else 100 / 105
    )
    # norm_factor for all elements on the pitch that are scaled in the y direction
    norm_factor_y = (
        1
        if unit == "m"
        else 100
        if unit == "cm"
        else 100 / width
        if width
        else 100 / 68
    )

    # All the positions and ranges of certain elements on the pitch
    # (i.e the penalty area) have fixed sizes and are scaled based on the
    # x and y norm factors.

    # key positions for the football pitch
    xmin, xmax = xlim
    ymin, ymax = ylim
    x_half = (xmax + xmin) / 2
    y_half = (ymax + ymin) / 2
    x_radius_points = 0.25 * norm_factor_x * 2
    y_radius_points = 0.25 * norm_factor_y * 2
    x_goal_height = 2.44 * norm_factor_x
    y_goal_width = 7.32 * norm_factor_y
    y_range_center_to_post = y_goal_width / 2

    # goal area
    x_pos_left_side_goal_area_line = xmin + 5.5 * norm_factor_x
    x_pos_right_side_goal_area_line = xmax - 5.5 * norm_factor_x
    y_pos_lower_goal_area = y_half - 9.16 * norm_factor_y
    y_pos_upper_goal_area = y_half + 9.16 * norm_factor_y

    # goal
    y_pos_goal_lower_post = y_half - y_range_center_to_post
    y_pos_goal_upper_post = y_half + y_range_center_to_post

    # penalty area
    x_pos_left_side_penalty_area_line = xmin + 16.5 * norm_factor_x
    y_pos_penalty_area_lower_line = y_half - 20.16 * norm_factor_y
    y_pos_penalty_area_upper_line = y_half + 20.16 * norm_factor_y
    x_pos_right_side_penalty_area_line = xmax - 16.5 * norm_factor_x
    x_pos_left_side_center_penalty_arc = xmin + 11 * norm_factor_x
    x_pos_right_side_center_penalty_arc = xmax - 11 * norm_factor_x
    x_pos_left_side_penalty_point = xmin + 11 * norm_factor_x
    x_pos_right_side_penalty_point = xmax - 11 * norm_factor_x

    # center circle
    x_radius_center_circle = 9.15 * norm_factor_x * 2
    y_radius_center_circle = 9.15 * norm_factor_y * 2

    # angle for the penalty area arc changes when unit is 'percent'
    angle = 10 if unit == "percent" else 0

    # field boundaries
    ax.plot(
        [xmin, xmax],
        [ymin, ymin],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmin, xmax],
        [ymax, ymax],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmin, xmin],
        [ymin, ymax],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmax, xmax],
        [ymin, ymax],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [x_half, x_half],
        [ymin, ymax],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )

    # goal area
    # goal area left
    ax.plot(
        [x_pos_left_side_goal_area_line, x_pos_left_side_goal_area_line],
        [y_pos_lower_goal_area, y_pos_upper_goal_area],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmin, x_pos_left_side_goal_area_line],
        [y_pos_lower_goal_area, y_pos_lower_goal_area],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmin, x_pos_left_side_goal_area_line],
        [y_pos_upper_goal_area, y_pos_upper_goal_area],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    # goal area right
    ax.plot(
        [x_pos_right_side_goal_area_line, x_pos_right_side_goal_area_line],
        [y_pos_lower_goal_area, y_pos_upper_goal_area],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmax, x_pos_right_side_goal_area_line],
        [y_pos_lower_goal_area, y_pos_lower_goal_area],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmax, x_pos_right_side_goal_area_line],
        [y_pos_upper_goal_area, y_pos_upper_goal_area],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )

    # penalty area
    # penalty area left
    ax.plot(
        [x_pos_left_side_penalty_area_line, x_pos_left_side_penalty_area_line],
        [y_pos_penalty_area_lower_line, y_pos_penalty_area_upper_line],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmin, x_pos_left_side_penalty_area_line],
        [y_pos_penalty_area_lower_line, y_pos_penalty_area_lower_line],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmin, x_pos_left_side_penalty_area_line],
        [y_pos_penalty_area_upper_line, y_pos_penalty_area_upper_line],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    # penalty area right
    ax.plot(
        [
            x_pos_right_side_penalty_area_line,
            x_pos_right_side_penalty_area_line,
        ],
        [y_pos_penalty_area_lower_line, y_pos_penalty_area_upper_line],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmax, x_pos_right_side_penalty_area_line],
        [y_pos_penalty_area_lower_line, y_pos_penalty_area_lower_line],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmax, x_pos_right_side_penalty_area_line],
        [y_pos_penalty_area_upper_line, y_pos_penalty_area_upper_line],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    # penalty point
    # left
    ax.add_patch(
        Arc(
            (x_pos_left_side_penalty_point, y_half),
            width=x_radius_points,
            height=y_radius_points,
            angle=0,
            theta1=0,
            theta2=360,
            color=color_contour_lines,
            zorder=zorder,
            linewidth=linewidth,
        )
    )
    # right
    ax.add_patch(
        Arc(
            (x_pos_right_side_penalty_point, y_half),
            width=x_radius_points,
            height=y_radius_points,
            angle=0,
            theta1=0,
            theta2=360,
            color=color_contour_lines,
            zorder=zorder,
            linewidth=linewidth,
        )
    )
    # penalty area circle left
    ax.add_patch(
        Arc(
            (x_pos_left_side_center_penalty_arc, y_half),
            width=x_radius_center_circle,
            height=y_radius_center_circle,
            angle=0,
            theta1=307.5 - angle,
            theta2=52.5 + angle,
            color=color_contour_lines,
            zorder=zorder,
            linewidth=linewidth,
        )
    )
    # penalty area circle right
    ax.add_patch(
        Arc(
            (x_pos_right_side_center_penalty_arc, y_half),
            width=x_radius_center_circle,
            height=y_radius_center_circle,
            angle=0,
            theta1=127.5 - angle,
            theta2=232.5 + angle,
            color=color_contour_lines,
            zorder=zorder,
            linewidth=linewidth,
        )
    )
    # goal
    # left goal
    ax.plot(
        [xmin - x_goal_height, xmin - x_goal_height],
        [y_pos_goal_lower_post, y_pos_goal_upper_post],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmin - x_goal_height, xmin],
        [y_pos_goal_upper_post, y_pos_goal_upper_post],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmin - x_goal_height, xmin],
        [y_pos_goal_lower_post, y_pos_goal_lower_post],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    # right goal
    ax.plot(
        [xmax + x_goal_height, xmax + x_goal_height],
        [y_pos_goal_lower_post, y_pos_goal_upper_post],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmax + x_goal_height, xmax],
        [y_pos_goal_upper_post, y_pos_goal_upper_post],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )
    ax.plot(
        [xmax + x_goal_height, xmax],
        [y_pos_goal_lower_post, y_pos_goal_lower_post],
        color=color_contour_lines,
        zorder=zorder,
        linewidth=linewidth,
    )

    # center circle
    ax.add_patch(
        Arc(
            (x_half, y_half),
            width=x_radius_center_circle,
            height=y_radius_center_circle,
            angle=0,
            theta1=0,
            theta2=360,
            color=color_contour_lines,
            zorder=zorder,
            linewidth=linewidth,
        )
    )
    # center point
    ax.add_patch(
        Arc(
            (x_half, y_half),
            width=x_radius_points,
            height=y_radius_points,
            angle=0,
            theta1=0,
            theta2=360,
            color=color_contour_lines,
            zorder=zorder,
            linewidth=linewidth,
        )
    )

    # remove labels and ticks
    if not show_axis_ticks:
        ax.xaxis.set_major_locator(matplotlib.ticker.NullLocator())
        ax.yaxis.set_major_locator(matplotlib.ticker.NullLocator())

    return ax
