import dearpygui.dearpygui as dpg

import numpy as np
import threading

from constants import *

def get_current_ui_type():
    for child in dpg.get_item_children('ui', 1):
        if dpg.get_value(child):
            return dpg.get_item_alias(child)

def get_current_theme():
    for child in dpg.get_item_children('theme', 1):
        if dpg.get_value(child):
            return dpg.get_item_alias(child)

def get_config_file_path():
    return dpg.get_item_user_data('main')['config_file_path']

def get_config():
    return dpg.get_item_user_data('main')['config']

def set_main_window_value(key, value):
    data = dpg.get_item_user_data('main')
    data[key] = value
    dpg.set_item_user_data('main', data)

def get_height_map_path():
    return dpg.get_item_user_data('map_window')['height_map_file_path']

def get_height_map():
    return dpg.get_item_user_data('map_window')['height_map']

def is_drawing():
    return dpg.get_item_user_data('map_window')['drawing']

def get_prev_coords():
    return dpg.get_item_user_data('map_window')['prev_coords']

def get_current_action():
    return dpg.get_item_user_data('map_window')['current_action']

def set_map_window_value(key, value):
    data = dpg.get_item_user_data('map_window')
    data[key] = value
    dpg.set_item_user_data('map_window', data)

def show_status_text(message):
    dpg.set_item_pos('status_text', (dpg.get_item_width('main') - dpg.get_text_size(message)[0] - 2 * SPACE, dpg.get_item_pos('status_text')[1]))
    dpg.set_value('status_text', message)

def path_iter(path, prefix=""):
    namespaces = path.split('.')
    for i in range(len(namespaces)):
        yield prefix + '.' + '.'.join(namespaces[:i+1])

def delete_item_and_clear_alias(item):
    alias = dpg.get_item_alias(item)
    if alias:
        dpg.remove_alias(alias)
    if dpg.does_item_exist(item):
        dpg.delete_item(item)

def delete_item_children_and_clear_aliases_(item):
    if dpg.does_item_exist(item):
        for child in dpg.get_item_children(item, 1):
            delete_item_children_and_clear_aliases_(child)
            delete_item_and_clear_alias(child)

def delete_item_children_and_clear_aliases():
    if len(dpg.get_item_children('main', 1)) > 1:
        delete_item_children_and_clear_aliases_(dpg.get_item_children('main', 1)[1])
        delete_item_and_clear_alias(dpg.get_item_children('main', 1)[1])

####################################################################################
#
#    search utils
#
####################################################################################

def change_color_temporarily(text_tag, color, duration=1):
    color = list(color)[:-1] + [255]
    dpg.configure_item(text_tag, color=color)
    threading.Timer(duration, lambda: revert_color(text_tag)).start()

def revert_color(text_tag):
    dpg.configure_item(text_tag, color=(255, 255, 255, 255))

####################################################################################
#
#    edit map utils
#
####################################################################################

def update_texture(height_map):
    max_height = np.max(height_map)
    normalized_map = height_map / max_height

    texture_data = normalized_map.flatten()
    texture_data = np.tile(texture_data, (4, 1)).T.flatten()

    texture_data.resize(800 * 800 * 4)

    width, height = height_map.shape

    dpg.set_value('heatmap_texture', texture_data)

def check_coords(x, y, w, h):
    mx, my = dpg.get_item_pos('map')
    mw, mh = dpg.get_item_width('map'), dpg.get_item_height('map')

    return mx <= x <= x + w <= mx + mw and my <= y <= y + h <= my + mh

def apply_tint(color, tint=(0, 119, 200)):
    tint = np.array(tint) / 255
    color = np.array(color) / 255
    color *= tint
    return list(map(int, (color * 255)))

def adjust_coords(coords):
    x, y = coords
    return int(x - dpg.get_item_pos('map')[0] + dpg.get_x_scroll('map_window')), int(y - dpg.get_item_pos('map')[1] + dpg.get_text_size('edit map')[1] + 2 * SPACE + dpg.get_y_scroll('map_window'))

def get_rect(cur_pos, end_pos):
    x1, y1 = adjust_coords(cur_pos)
    x2, y2 = adjust_coords(end_pos)

    if y2 < y1:
        y1, y2 = y2, y1

    if x2 < x1:
        x1, x2 = x2, x1

    return y1, y2, x1, x2

def load_height_map(file_path):
    with open(file_path, "r") as file:
        lines = file.readlines()[1:]
        height_map = [list(map(int, line.strip().split())) for line in lines]
    return np.array(height_map)

def dump_map(height_map, file_path):
    with open(file_path, "w", encoding="utf-8") as file:
        w, h = height_map.shape
        file.write(f"{w} {h}\n")
        for row in height_map:
            file.write(" ".join(list(map(str, row))) + "\n")

####################################################################################
#
#    main menu utils
#
####################################################################################

def combo_menu(callback):
    def func(s, a, u):
        for child in dpg.get_item_children(dpg.get_item_parent(s), 1):
            if dpg.get_item_alias(child) != dpg.get_item_alias(s):
                dpg.set_value(child, False)
            else:
                dpg.set_value(child, True)
        dpg.set_item_user_data(s, dpg.get_item_alias(s))
        callback(s, a, u)
    return func

####################################################################################
#
#    tabs ui utils
#
####################################################################################

def does_tab_bar_child_exist(item):
    for uuid in dpg.get_item_children(item, 1):
        if dpg.get_item_type(uuid) == "mvAppItemType::mvTabBar":
            return True, uuid
    return False, None

def get_absolute_y(item):
    y = dpg.get_item_pos(item)[1]
    parent = dpg.get_item_parent(item)
    while parent:
        if dpg.get_item_type(parent) == 'mvAppItemType::mvChildWindow':
            y += dpg.get_item_pos(parent)[1]
        parent = dpg.get_item_parent(parent)
    return y

def get_item_level(item):
    level = 0
    parent = dpg.get_item_parent(item)
    while parent:
        if dpg.get_item_type(parent) == 'mvAppItemType::mvTabBar':
            level += 1
        parent = dpg.get_item_parent(parent)
    return level

def change_height(item):    
    if not dpg.does_item_exist(item):
        return
    if dpg.get_item_type(item) == 'mvAppItemType::mvChildWindow':
        uuid = dpg.get_item_parent(item)
        new_height = dpg.get_viewport_client_height() - get_absolute_y(uuid) - SPACE * get_item_level(item)

        dpg.set_item_height(item, max(new_height, dpg.get_item_user_data(item)))

    for child in dpg.get_item_children(item, 1):
        change_height(child)