import pygetwindow as gw  # Get size & coords of specific window with It's handle(hwnd), not title
from pywinauto import Desktop # Get size & coords of specific window with It's title   *USE THIS!!!*
from mss import mss # Capture windows with given coords
import cv2  # You know what It is
import numpy as np  # sure
import time
from skimage.metrics import structural_similarity as ssim

def resize_with_ratio(image, scale=1.5, inter=cv2.INTER_LINEAR):
    # 이미지 크기 가져오기
    (h, w) = image.shape[:2]
    
    # 너비와 높이를 1.5배로 확대
    new_size = (int(w * scale), int(h * scale))
    
    # 리사이즈 적용
    resized = cv2.resize(image, new_size, interpolation=inter)
    
    return resized

def pad_to_match_size(card1, card2):
    # 카드 1과 카드 2의 크기 확인
    h1, w1 = card1.shape[:2]
    h2, w2 = card2.shape[:2]
    
    # 두 카드의 최대 너비와 높이 계산
    max_h = max(h1, h2)
    max_w = max(w1, w2)
    
    # 카드 1에 패딩 추가 (상하좌우에 패딩을 균일하게 추가)
    pad_top_1 = (max_h - h1) // 2
    pad_bottom_1 = max_h - h1 - pad_top_1
    pad_left_1 = (max_w - w1) // 2
    pad_right_1 = max_w - w1 - pad_left_1
    padded_card1 = cv2.copyMakeBorder(card1, pad_top_1, pad_bottom_1, pad_left_1, pad_right_1, cv2.BORDER_CONSTANT, value=[0, 0, 0])
    
    # 카드 2에 패딩 추가
    pad_top_2 = (max_h - h2) // 2
    pad_bottom_2 = max_h - h2 - pad_top_2
    pad_left_2 = (max_w - w2) // 2
    pad_right_2 = max_w - w2 - pad_left_2
    padded_card2 = cv2.copyMakeBorder(card2, pad_top_2, pad_bottom_2, pad_left_2, pad_right_2, cv2.BORDER_CONSTANT, value=[0, 0, 0])
    
    return padded_card1, padded_card2

# def compare_cards(card1, card2): #============================================= L2 norm
#   resized_card1, resized_card2 = pad_to_match_size(card1, card2)
#   return cv2.norm(resized_card1, resized_card2, cv2.NORM_L2)

# def compare_cards(card1, card2): #============================================= ORB
  # orb = cv2.ORB_create()

  # # 카드에서 특징점 검출
  # kp1, des1 = orb.detectAndCompute(card1, None)
  # kp2, des2 = orb.detectAndCompute(card2, None)

  # # BFMatcher로 특징점 매칭
  # bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
  # matches = bf.match(des1, des2)

  # # 매칭 결과를 거리 기준으로 정렬
  # matches = sorted(matches, key=lambda x: x.distance)

  # # 거리 합산으로 차이 계산 (거리가 클수록 더 많은 차이)
  # return sum([match.distance for match in matches])

# def compare_cards(card1, card2): #============================================= 정적배경차분
#   resized_card1, resized_card2 = pad_to_match_size(card1, card2)
  
#   # 이미지 차이 계산
#   diff = cv2.absdiff(resized_card1, resized_card2)
  
#   # 차이가 나는 픽셀의 합계를 계산
#   difference_score = np.sum(diff)
  
#   return difference_score

# def compare_cards(card1, card2): #============================================= Canny edge detection
#   resized_card1, resized_card2 = pad_to_match_size(card1, card2)
  
#   # Canny Edge Detection 적용
#   edges1 = cv2.Canny(resized_card1, 30, 150)
#   edges2 = cv2.Canny(resized_card2, 30, 150)

#   # 이미지 차이 계산 (엣지 차이)
#   diff = cv2.absdiff(edges1, edges2)
  
#   # 차이가 나는 픽셀의 합계를 계산
#   difference_score = np.sum(diff)

#   return difference_score

# def compare_cards(card1, card2): #============================================= 히스토그램 비교
#   resized_card1, resized_card2 = pad_to_match_size(card1, card2)
  
#   # 히스토그램 계산
#   hist1 = cv2.calcHist([resized_card1], [0], None, [256], [0, 256])
#   hist2 = cv2.calcHist([resized_card2], [0], None, [256], [0, 256])
  
#   # 히스토그램을 정규화
#   hist1 = cv2.normalize(hist1, hist1)
#   hist2 = cv2.normalize(hist2, hist2)
  
#   # 히스토그램 차이 계산 (Chi-Square 비교)
#   score = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CHISQR)
  
#   return score

# def compare_cards(card1, card2): #============================================= 템플릿 매칭
#   resized_card1, resized_card2 = pad_to_match_size(card1, card2)
  
#   # 템플릿 매칭
#   result = cv2.matchTemplate(resized_card1, resized_card2, cv2.TM_CCOEFF_NORMED)
  
#   # 매칭 값 (1에 가까울수록 유사, 0에 가까울수록 차이)
#   min_val, max_val, _, _ = cv2.minMaxLoc(result)
  
#   return max_val


# def compare_cards(card1, card2): #============================================= 로그적용 정적배경차분
#   resized_card1, resized_card2 = pad_to_match_size(card1, card2)
  
#   # LoG 필터 적용
#   log_card1 = cv2.Laplacian(cv2.GaussianBlur(resized_card1, (3, 3), 0), cv2.CV_64F)
#   log_card2 = cv2.Laplacian(cv2.GaussianBlur(resized_card2, (3, 3), 0), cv2.CV_64F)
#   # log_card1 = cv2.Laplacian(resized_card1, cv2.CV_64F)
#   # log_card2 = cv2.Laplacian(resized_card2, cv2.CV_64F)
  
#   # 이미지 차이 계산
#   diff = cv2.absdiff(log_card1, log_card2)
  
#   # 차이 합계 계산
#   difference_score = np.sum(diff)
  
#   return difference_score


def compare_cards(card1, card2): #============================================= SSIM
    resized_card1, resized_card2 = pad_to_match_size(card1, card2)
    
    # SSIM 비교 (grayscale로 변환한 후)
    ssim_score, _ = ssim(resized_card1, resized_card2, full=True)
    
    return ssim_score


target_window = "S22 Ultra"
windows = Desktop(backend="uia").windows()

selected_window = None
for w in windows:
  if target_window.lower() in w.window_text().lower():  # 대소문자 구분 없이 비교
    selected_window = w
    break

if selected_window != None:
  rect = selected_window.rectangle()
  monitor_coords = {"top": rect.top, "left": rect.left, "width": rect.width(), "height": rect.height()}
  
  with mss() as sct:
    while True:
      rect = selected_window.rectangle()
      monitor_coords = {"top": rect.top, "left": rect.left, "width": rect.width(), "height": rect.height()}


      sct_img = sct.grab(monitor_coords)
      img = np.array(sct_img)

      # Now we're gonna do some CV things

      # Preprocessing
      gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
      blur = cv2.GaussianBlur(gray, (5, 5), 0)
      _, thresh = cv2.threshold(blur, 245, 255, cv2.THRESH_BINARY_INV)

      kernel = np.ones((3, 3), np.uint8)
      thresh = cv2.erode(thresh, kernel, iterations=1)
      _, thresh = cv2.threshold(thresh, 100, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

      # Find contour
      contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
      cv2.imshow("Preprocessed", thresh)


      cards = []
      for i, cnt in enumerate(contours):
        x, y, w, h = cv2.boundingRect(cnt)
        if 60 < w < 200 and 100 < h < 300:  # 카드 크기
          aspect_ratio = float(w) / h
          if 0.5 < aspect_ratio < 1.0:  # 카드 비율
            card_gray = gray[y:y+h, x:x+w]
            card_resized = resize_with_ratio(card_gray, 2)
            _, card_thresh = cv2.threshold(card_resized, 130, 255, cv2.THRESH_BINARY_INV)
            card_kernel = np.ones((1, 1), np.uint8)  # 커널 크기로 글자 두께 조절
            card_eroded = cv2.erode(card_thresh, card_kernel, iterations=1)
            cv2.imshow("card", card_eroded)
            cards.append((card_eroded, cnt))  # 카드 이미지와 윤곽선 정보 함께 저장
            cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

      # 차이 계산
      differences = []
      if len(cards) > 1:
        for i in range(len(cards)):
          min_diff = float('inf')  # 비교 시 최소값을 찾기 위한 초기값 설정
          card_image_1, _ = cards[i]  # 기준 카드 이미지

          for j in range(len(cards)):
            if i != j:  # 자기 자신과는 비교하지 않음
              card_image_2, _ = cards[j]  # 비교할 다른 카드 이미지
              diff = compare_cards(card_image_1, card_image_2)  # 두 카드 이미지 비교
              if diff < min_diff:
                min_diff = diff  # 최소 차이값 업데이트
          
          differences.append((i, min_diff)) 

      # 차이비교
      if differences:
        max_different_card = max(differences, key=lambda x: x[1])  # 차이가 가장 큰 카드 (간혹 방식에 따라 반대일 수 있음)
        min_different_card = min(differences, key=lambda x: x[1])  # 차이가 가장 작은 카드

        # 가장 큰 차이가 있는 카드의 윤곽선
        _, cnt_max = cards[max_different_card[0]]
        x_max, y_max, w_max, h_max = cv2.boundingRect(cnt_max)
        cv2.rectangle(img, (x_max, y_max), (x_max + w_max, y_max + h_max), (0, 0, 255), 2)  # 빨간색
        cv2.putText(img, f'Conf: {max_different_card}%', (x_max, y_max - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 0, 0), 2)

        # 가장 작은 차이가 있는 카드의 윤곽선
        _, cnt_min = cards[min_different_card[0]]
        x_min, y_min, w_min, h_min = cv2.boundingRect(cnt_min)
        cv2.rectangle(img, (x_min, y_min), (x_min + w_min, y_min + h_min), (255, 0, 0), 2)  # 파란색
        cv2.putText(img, f'Conf: {min_different_card}%', (x_min, y_min - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 0, 0), 2)

      print("\rtotal cards: {}".format(len(cards)), end="")
      cv2.imshow("Capturing target", img)

      if cv2.waitKey(1) & 0xFF == ord('q'):
        break
      
  cv2.destroyAllWindows()