import cv2
import numpy as np
from sklearn import cluster
import os
# Setting up the blob detector
params = cv2.SimpleBlobDetector_Params()

params.filterByInertia
params.minInertiaRatio = 0.6

detector = cv2.SimpleBlobDetector_create(params)

def get_blobs(frame):
    #frame_blurred = cv2.medianBlur(frame, 3)
    #frame_gray = cv2.cvtColor(frame_blurred, cv2.COLOR_BGR2GRAY)
    blobs = detector.detect(frame)

    return blobs


def get_dice_from_blobs(blobs):
    # Get centroids of all blobs
    X = []
    for b in blobs:
        pos = b.pt

        if pos != None:
            X.append(pos)

    X = np.asarray(X)

    if len(X) > 0:
        # Important to set min_sample to 0, as a dice may only have one dot
        clustering = cluster.DBSCAN(eps=150, min_samples=1).fit(X)

        # Find the largest label assigned + 1, that's the number of dice found
        num_dice = max(clustering.labels_) + 1

        dice = []

        # Calculate centroid of each dice, the average between all a dice's dots
        for i in range(num_dice):
            X_dice = X[clustering.labels_ == i]

            centroid_dice = np.mean(X_dice, axis=0)

            dice.append([len(X_dice), *centroid_dice])

        return dice

    else:
        return []




def overlay_info(frame, dice, blobs):
    # Overlay blobs
    for b in blobs:
        pos = b.pt
        r = b.size / 2

        cv2.circle(frame, (int(pos[0]), int(pos[1])),
                   int(r), (255, 0, 0), 2)

    # Overlay dice number
    for d in dice:
        # Get textsize for text centering
        textsize = cv2.getTextSize(
            str(d[0]), cv2.FONT_HERSHEY_PLAIN, 3, 2)[0]

        cv2.putText(frame, str(d[0]),
                    (int(d[1] - textsize[0] / 2),
                     int(d[2] + textsize[1] / 2)),
                    cv2.FONT_HERSHEY_PLAIN, 3, (0, 255, 0), 2)
        
# standard edge detection filter
def edge_bb_dice(image):
 
    gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray_img, (7, 7), 0)
    detected_edges = cv2.Canny(blurred, 150, 200)
    
    cropped = gray_img
    filtered = detected_edges
 
    nonzero_coords = np.column_stack(np.where(filtered > 0.0))
 
    if len(nonzero_coords) > 0:
        min_y, min_x = np.min(nonzero_coords, axis=0)
        max_y, max_x = np.max(nonzero_coords, axis=0)
 
        # padding = 20
        # min_x = max(0, min_x - padding // 2)
        # min_y = max(0, min_y - padding // 2)
        # max_x = min(image.shape[1], max_x + padding // 2)
        # max_y = min(image.shape[0], max_y + padding // 2)
 
        cropped = gray_img[min_y:max_y, min_x:max_x]
 
        #image_with_bb = np.copy(image)
        #cv2.rectangle(image_with_bb, (min_x, min_y), (max_x, max_y), (0, 255, 0), 2)
 
    return image, filtered, cropped  




# Initialize a video feed
cap = cv2.VideoCapture(1)
#  16:9 (544x306 -> 30fps with edge_bb_dice)
cap.set(3, 544)
cap.set(4, 306)

last_dice = 0
frame_counter = 0
label_counter = 0
can_throw = True

current_path = f'../bossfight/assets/current_roll.jpg'
previous_path = f'../bossfight/assets/previous_roll.jpg'
current_roll = cv2.imread(current_path)

while(True):
    # Grab the latest image from the video feed
    ret, frame = cap.read()
    #temp = frame.copy()

    image, filtered, cropped = edge_bb_dice(frame)
    
    # We'll define these later
    blobs = get_blobs(cropped)
    dice = get_dice_from_blobs(blobs)
    out_frame = overlay_info(cropped, dice, blobs)

    
    # cv2.imshow("frame", image)
    # cv2.imshow("frame2", filtered)
    # cv2.imshow("frame3", cropped)

    for d in dice:
        if last_dice == d[0]:
            frame_counter += 1
            if frame_counter > 17 and can_throw:
                frame_counter = 0

                cv2.imwrite(current_path, cropped)
                cv2.imwrite(previous_path, current_roll)
                current_roll = cropped

                label_counter += 1
                s = f'\n{label_counter},{d[0]}'
                with open('../bossfight/dice_roll_data.csv','a') as fd:
                    fd.write(s)
                print(s)
                can_throw = False
        else:
            frame_counter = 0
        last_dice = d[0]
    if not dice:
        can_throw = True
        last_dice = 0

    


    res = cv2.waitKey(1)

    # Stop if the user presses "q"
    if res & 0xFF == ord('q'):
        break

# When everything is done, release the capture
cap.release()
cv2.destroyAllWindows()