import PIL.Image, PIL.ImageDraw, PIL.ImageFilter, PIL.ImageFont, PIL.ImageOps
from ..image import image_line, image_rectangle
from ..image.utilities import _coord_line
from ..psychopy import psychopy_line, psychopy_rectangle


def rodframe_psychopy(window, parameters=None, **kwargs):
    """Create a PsychoPy stimulus of the Rod and frame illusion.
    
    
    The Rod and frame illusion is an optical illusion causing the participant to
    perceive the rod to be oriented congruent with the orientation of the frame.

    Parameters
    ----------
    window : object
        The window object in which the stimulus will be rendered.
    parameters : dict
        Parameters of the Rod and frame illusion generated by `rodframe_psychopy()`.
    **kwargs
        Additional arguments passed into `rodframe_psychopy()`.
    
    Returns
    -------
    In-place modification of the PsychoPy window (No explicit return).

    Examples
    ---------
    >>> import pyllusion as ill
    >>> from psychopy import visual, event

    >>> # Create parameters
    >>> parameters = ill.rodframe_parameters(illusion_strength=11)

    >>> # Initiate Window
    >>> window = visual.Window(size=[800, 600], winType='pygame', color="white")
    
    >>> # Display illusion
    >>> ill.rodframe_psychopy(window=window, parameters=parameters)
    
    >>> # Refresh and close window    
    >>> window.flip()
    >>> event.waitKeys()  # Press any key to close
    >>> window.close()
    """
    
    # Create white canvas and get drawing context
    if parameters is None:
        parameters = rodframe_parameters(**kwargs)

    # Frame
    psychopy_rectangle(window, x=0, y=0,
                       size_width=1, size_height=1,
                       color="white", outline_color="black", outline=5,
                       rotate=parameters["Frame_Angle"], adjust_width=True)

    # Rod
    psychopy_line(window, x=0, y=0, length=0.8, rotate=parameters["Rod_Angle"],
                  adjust_width=True, color="red", size=5)
                 

def rodframe_image(
    parameters=None, width=800, height=600, outline=20, background="white", **kwargs
):
    """Create a PIL image of the Rod and frame illusion.
    
    
    The Rod and frame illusion is an optical illusion causing the participant to
    perceive the rod to be oriented congruent with the orientation of the frame.

    Parameters
    ----------
    parameters : dict
        Parameters of the Rod and frame illusion generated by `rodframe_parameters()`.
    width : int
        Width of the returned image.
    height : int
        Height of the returned image.
    outline : float
        The width of the rod in the illusion, passed into `image_line()`, and the width of the 
        rectangle border, passed into `image_rectangle()`.
    background : str
        Color of the background.
    **kwargs
        Additional arguments passed into `rodframe_parameters()`.

    Returns
    -------
    Image
        Image of the Rod and frame illusion, defaults to 800 x 600 pixels.
        Can be resized
        (`resize()`, See https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.resize)
        and saved in different file formats
        (`save()` See https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html).
        
    Examples
    ---------
    >>> import pyllusion as ill
    >>>
    >>> parameters = ill.rodframe_parameters(illusion_strength=11, difference=0)
    >>> ill.rodframe_image(parameters)
    
    >>> parameters = ill.rodframe_parameters(illusion_strength=20, difference=20)
    >>> ill.rodframe_image(parameters)
    """
    # Create white canvas and get drawing context
    if parameters is None:
        parameters = rodframe_parameters(**kwargs)

    # Background
    image = PIL.Image.new("RGB", (width, height), color=background)

    # Frame
    image = image_rectangle(
        image=image,
        size_width=1,
        size_height=1,
        rotate=parameters["Frame_Angle"],
        color=(0, 0, 0, 0),
        outline=outline,
        adjust_width=True,
    )

    # Rod
    coord, _, _ = _coord_line(x=0, y=0, length=0.8, angle=parameters["Rod_Angle"])
    x1, y1, x2, y2 = coord

    image = image_line(
        image=image,
        x1=x1,
        y1=y1,
        x2=x2,
        y2=y2,
        length=None,
        rotate=None,
        color="red",
        size=outline,
        adjust_width=True,
    )

    return image


def rodframe_parameters(illusion_strength=0, difference=0):
    """
    Compute Parameters for the Rod and Frame Illusion

    Parameters
    ----------
    illusion_strength : float
        The strength of the frame tilt in biasing the perception of a congruently tilted rod.
        Specifically, the orientation of the frame in degrees, 0 being vertical and positive values rotating clockwise, and
        negative values rotating anticlockwise.
    difference : float
        The objective tilt of the rod.
        Specifically, the orientation of the rod in degrees, 0 being vertical and positive values rotating clockwise, and
        negative values rotating anticlockwise.

    Returns
    -------
    dict
        Dictionary of parameters of the Rod and Frame illusion.
    """
    rod_angle = difference

    if difference >= 0:
        frame_angle = illusion_strength
    else:
        frame_angle = -1 * illusion_strength

    parameters = {
        "Illusion": "RodFrame",
        "Frame_Angle": frame_angle,
        "Rod_Angle": rod_angle,
        "Angle_Difference": rod_angle - frame_angle,
        "Difference": difference,
        "Illusion_Strength": illusion_strength,
        "Illusion_Type": "Congruent" if illusion_strength > 0 else "Incongruent",
    }

    return parameters
