import cv2
import time
import datetime
import numpy as np
import io
from PIL import Image
from io import BytesIO
from ppadb.client import Client as AdbClient
from PIL import Image

client = AdbClient(host="127.0.0.1", port=5037)
device = client.device("192.168.178.32:5555")

# template positions
close_sub_fights = cv2.imread('templates/close_sub_fights.jpg')
close_fight = cv2.imread('templates/close_fight.jpg')
fight_button = cv2.imread('templates/i.jpg')
end_of_log = cv2.imread('templates/end_of_log.jpg')
end_of_log2 = cv2.imread('templates/end_of_log2.jpg')

# cursor positions
fight_scroll_top = "2494 626"
fight_scroll_bottom = "2200 1520"
titan_fight = "1400 860"
damage_taken = "450 850"
close_details = "2175 450"
close_titan_fight = "2650 570"
defense_log = "350 870"

def non_max_suppression(boxes, overlapThresh):
  if len(boxes) == 0:
    return []

  # Convert to float
  boxes = np.array(boxes, dtype="float")

  # Initialize the list of picked indexes
  pick = []

  # Grab the coordinates of the bounding boxes
  x1 = boxes[:,0]
  y1 = boxes[:,1]
  x2 = boxes[:,2]
  y2 = boxes[:,3]

  # Compute the area of the bounding boxes and sort by bottom-right y-coordinate
  area = (x2 - x1 + 1) * (y2 - y1 + 1)
  idxs = np.argsort(y2)

  # Keep looping while some indexes still remain in the indexes list
  while len(idxs) > 0:
    # Grab the last index in the indexes list and add the index value to the list of picked indexes
    last = len(idxs) - 1
    i = idxs[last]
    pick.append(i)

    # Find the largest (x, y) coordinates for the start of the bounding box and the smallest (x, y)
    # coordinates for the end of the bounding box
    xx1 = np.maximum(x1[i], x1[idxs[:last]])
    yy1 = np.maximum(y1[i], y1[idxs[:last]])
    xx2 = np.minimum(x2[i], x2[idxs[:last]])
    yy2 = np.minimum(y2[i], y2[idxs[:last]])

    # Compute the width and height of the bounding box
    w = np.maximum(0, xx2 - xx1 + 1)
    h = np.maximum(0, yy2 - yy1 + 1)

    # Compute the ratio of overlap
    overlap = (w * h) / area[idxs[:last]]

    # Delete all indexes from the index list that have overlap greater than the threshold
    idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlapThresh)[0])))

  # Return only the bounding boxes that were picked
  return boxes[pick].astype("int")

def screen_has_changed(prev_screenshot, threshold=0.01):
  # Take a new screenshot
  current_screenshot = device.screencap()

  # Convert to NumPy arrays
  prev_img = np.frombuffer(prev_screenshot, dtype=np.uint8)
  current_img = np.frombuffer(current_screenshot, dtype=np.uint8)

  # Load images
  prev_img = cv2.imdecode(prev_img, cv2.IMREAD_COLOR)
  current_img = cv2.imdecode(current_img, cv2.IMREAD_COLOR)

  # Calculate absolute difference
  diff = cv2.absdiff(prev_img, current_img)
  non_zero_count = np.count_nonzero(diff)

  # print(f"diff: {non_zero_count} > {threshold * diff.size} = {non_zero_count > threshold * diff.size}")

  # Check if the difference is greater than the threshold
  return non_zero_count > threshold * diff.size

def save_screenshot():
  # Take a screenshot
  result = device.screencap()

  timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
  image = Image.open(io.BytesIO(result))
  jpeg_filename = f"/mnt/t/nextcloud/InstantUpload/Herowars/{timestamp}.jpg"

  image = image.convert('RGB')  # Convert to RGB mode for JPEG
  with open(jpeg_filename, "wb") as fp:
    image.save(fp, format='JPEG', quality=85)  # Adjust quality as needed

  time.sleep(0.5)

def wait_for_screen_change():
  # Usage example
  prev_screenshot = device.screencap()

  while not screen_has_changed(prev_screenshot):
    time.sleep(0.1)  # Polling interval

def tap(location):
  device.shell(f"input tap {location}")
  time.sleep(1)

def swipe(start, end):
  device.shell(f"input swipe {start} {end} 1000")
  time.sleep(0.5)

def tap_button(template):
  button = find_templates(template)
  if len(button) == 0:
    return
  tap(f"{button[0][0]} {button[0][1]}")

def is_end_of_log():
  templates = find_templates(end_of_log)
  if (len(templates) == 0):
    templates = find_templates(end_of_log2)

  result = len(templates) > 0

  if result:
    print("reached end of guild war log!")

  return result

def find_templates(template_image):
  screenshot = device.screencap()
  target_image = Image.open(BytesIO(screenshot))

  # Convert the image to a NumPy array and then to BGR format (which OpenCV uses)
  target_image = np.array(target_image)
  target_image = cv2.cvtColor(target_image, cv2.COLOR_RGB2BGR)

  w, h = template_image.shape[:-1]

  # Template matching
  result = cv2.matchTemplate(target_image, template_image, cv2.TM_CCOEFF_NORMED)

  # Define a threshold
  threshold = 0.9  # Adjust this threshold based on your requirements

  # Finding all locations where match exceeds threshold
  locations = np.where(result >= threshold)
  locations = list(zip(*locations[::-1]))

  # Create list of rectangles
  rectangles = [(*loc, loc[0] + w, loc[1] + h) for loc in locations]

  # Apply non-maximum suppression to remove overlaps
  rectangles = non_max_suppression(rectangles, 0.3)

  # Initialize an empty list to store coordinates
  coordinates = []

  for (startX, startY, endX, endY) in rectangles:
    # Calculate the center coordinates
    centerX = round(startX + (endX - startX) / 2)
    centerY = round(startY + (endY - startY) / 2)

    # Append the coordinate pair to the list
    coordinates.append((centerX, centerY))

  # Sort the coordinates by y value in ascending order
  return sorted(coordinates, key=lambda x: x[1])

def find_max_y_pair(coordinates):
    # find the coordinate pair with the maximum y value
    result = max(coordinates, key=lambda x: x[1])

    return f"{result[0]} {result[1]}"

def take_fight_screenshots():
  save_screenshot()
  tap(damage_taken)
  save_screenshot()
  tap_button(close_fight)

def process_war_log():
  buttons = find_templates(fight_button)

  if len(buttons) == 0:
    swipe(fight_scroll_bottom, fight_scroll_top)
    return

  # process all found buttons
  for pair in buttons:
      tap(f"{pair[0]} {pair[1]}")
      sub_buttons = find_templates(fight_button)
      if (len(sub_buttons) == 0):
        take_fight_screenshots()
      else:
        for pair2 in sub_buttons:
          tap(f"{pair2[0]} {pair2[1]}")
          take_fight_screenshots()
        tap_button(close_sub_fights)

  find_max_y_pair(buttons)
  swipe(find_max_y_pair(buttons), fight_scroll_top)

# start
while not is_end_of_log():
  process_war_log();

# possible duplicates here, but necessary to be sure to get the last fights
process_war_log();
