import cv2
import numpy as np
import numpy as np
import pygame
import pygame.gfxdraw
import pygame as pg
from random import randrange
import pymunk.pygame_util


def lower_update(value):
    global lower
    lower = value


def upper_update(value):
    global upper
    upper = value


def find_paper_and_crop(thres):
    global pp_rect, pp_dst, maxW, maxH

    contours, _ = cv2.findContours(thres, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    largest_contour = max(contours, key=cv2.contourArea)

    epsilon = 0.02 * cv2.arcLength(largest_contour, True)
    approx = cv2.approxPolyDP(largest_contour, epsilon, True)

    if len(approx) == 4:
        pts = approx.reshape(4, 2)
        rect = order_points(pts)
        (tl, tr, br, bl) = rect

        # print("Ordered points:", rect)
        widthA = np.linalg.norm(br - bl)
        widthB = np.linalg.norm(tr - tl)
        maxWidth = max(int(widthA), int(widthB))

        heightA = np.linalg.norm(tr - br)
        heightB = np.linalg.norm(tl - bl)
        maxHeight = max(int(heightA), int(heightB))

        dst = np.array(
            [
                [0, 0],
                [maxWidth, 0],
                [maxWidth, maxHeight],
                [0, maxHeight],
            ],
            dtype="float32",
        )
        pp_rect = rect
        pp_dst = dst
        maxW = maxWidth
        maxH = maxHeight
        warped = apply_perspective(thres, rect, dst, maxW, maxH)
        return warped
    else:
        raise Exception("Paper not detected or the paper does not have four corners")


def apply_perspective(image, rect, ppd, maxW, maxH):
    M = cv2.getPerspectiveTransform(rect, ppd)
    return cv2.warpPerspective(image, M, (maxW, maxH))


def order_points(pts):
    rect = np.zeros((4, 2), dtype="float32")
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    diff = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]
    return rect


def process_image(img):
    global pp_rect, pp_dst, maxW, maxH
    img = apply_perspective(img, pp_rect, pp_dst, maxW, maxH)
    img = cv2.resize(
        img,
        (0, 0),
        fx=1280 / img.shape[1],
        fy=800 / img.shape[0],
        interpolation=cv2.INTER_NEAREST_EXACT,
    )
    return img


def create_ball(space):
    ball_moment = pymunk.moment_for_circle(ball_mass, 0, ball_radius)
    ball_body = pymunk.Body(ball_mass, ball_moment)
    ball_body.position = 500, 100
    ball_shape = pymunk.Circle(ball_body, ball_radius)
    ball_shape.elasticity = 1
    ball_shape.friction = 1
    space.add(ball_body, ball_shape)
    return ball_body


def create_segment(from_, to_, thickness, space, color):
    segment_shape = pymunk.Segment(space.static_body, from_, to_, thickness)
    segment_shape.color = pg.color.THECOLORS[color]
    space.add(segment_shape)


def create_rect(x1, y1, x2, y2, x3, y3, x4, y4):
    # правый верх, левый верх, левый низ, левый верх
    color = "green"
    create_segment((x1, y1), (x2, y2), 3, space, color)
    create_segment((x2, y2), (x3, y3), 3, space, color)
    create_segment((x3, y3), (x4, y4), 3, space, color)
    create_segment((x4, y4), (x1, y1), 3, space, color)


pymunk.pygame_util.positive_y_is_up = False

# cv2.namedWindow("Image", cv2.WINDOW_GUI_NORMAL)
cv2.namedWindow("Mask", cv2.WINDOW_GUI_NORMAL)

# cap = cv2.VideoCapture(2)
# cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1)
# cap.set(cv2.CAP_PROP_EXPOSURE, 5)

lower = 0
upper = 55

cv2.createTrackbar("Lower", "Mask", lower, 255, lower_update)
cv2.createTrackbar("Upper", "Mask", upper, 255, upper_update)

pp_rect = []
pp_dst = []
maxW = 0
maxH = 0

# img = cap.read()[1]
img = cv2.imread("cllean.jpg")

img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# img = cv2.threshold(img, 10, 255, type=cv2.THRESH_BINARY)[1]
img = cv2.threshold(img, 10, 255, type=cv2.THRESH_BINARY)[1]

cv2.imshow("b", img)

# while True: cv2.waitKey(1)

crop = find_paper_and_crop(img)
# cv2.imshow("a", crop)

crop = cv2.resize(
    crop,
    (0, 0),
    fx=1280 / crop.shape[1],
    fy=800 / crop.shape[0],
    interpolation=cv2.INTER_NEAREST_EXACT,
)

RES = WIDTH, HEIGHT = 1280, 800
FPS = 60

surface = pg.display.set_mode((0, 0), pygame.FULLSCREEN, display=1)

# print(pg.display.get_desktop_sizes())
clock = pg.time.Clock()
draw_options = pymunk.pygame_util.DrawOptions(surface)

space = pymunk.Space()
space.gravity = 0, 1000
ball_mass, ball_radius = 1000000, 10

balls = [([randrange(256) for i in range(3)], create_ball(space)) for j in range(0)]

while True:
    #     bts = socket.recv()

    surface.fill(pg.Color("white"))

    space.step(1 / FPS)
    space.debug_draw(draw_options)
    for color, ball in balls:
        if (
            ball.position.x < -ball_radius
            or ball.position.x > WIDTH + ball_radius
            or ball.position.y < -ball_radius
            or ball.position.y > HEIGHT + ball_radius
        ):
            ball.position = 500, 100
            ball.velocity = (0, 0)

    pg.display.flip()
    clock.tick(FPS)

    # cv2.imshow("Image", frame2)

    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN and event.key == pygame.K_e:
            space.remove(*space.shapes)
            balls = [
                ([randrange(256) for i in range(3)], create_ball(space))
                for j in range(100)
            ]

            # aeae = cap.read()[1]
            aeae = cv2.imread("cllean.jpg")

            aeae = process_image(aeae)
            # frame = aeae.copy()
            # frame2 = frame.copy()
            gray = aeae.copy()
            #         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            gray = cv2.GaussianBlur(gray, (7, 7), 0)
            mask = cv2.Canny(gray, lower, upper)
            # cv2.imshow('Mask', mask)
            cnts, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            # for i in range(len(cnts)):
            #     cv2.drawContours(frame2, cnts, i, (0, 0, 0), 1)
            for index, cnt in enumerate(cnts):
                rect = cv2.minAreaRect(cnt)
                box = cv2.boxPoints(rect)
                box = np.int0(box)
                # cv2.drawContours(frame2, [box], 0, (0, 0, 255), 2)
                create_rect(*[a for b in box for a in b])

        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            cv2.destroyAllWindows()
            exit()
