import dearpygui.dearpygui as dpg

from utils import *
from callbacks import *
from constants import MAX_MAP_WIDTH, MAX_MAP_HEIGHT, EMISSION_POINT_COLOR
from dynamic_ui import construct_config_ui, add_emission_point_and_update_ui

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, dtype=np.float64)

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

def update_texture():
    if get_config_file_path():
        emission_points = get_emission_points()
        for n in emission_points:
            x = int(emission_points[n]['xpos'])
            y = int(emission_points[n]['ypos'])
            coords = get_triangle_coords(x, y)
            dpg.draw_polygon(coords, color=EMISSION_POINT_COLOR, fill=(255, 0, 0, 255), parent=f'{get_height_map_file_path()}map_drawlist', thickness=0)

    texture_map = np.repeat(get_map_window_value(f'{dpg.get_value('layer')}_map'), 4)

    print(texture_map.shape, np.all(texture_map == 0), f'map_{dpg.get_value('layer')}_texture', np.all(get_map_window_value(f'{dpg.get_value('layer')}_map') == 0))

    texture_map[3::4] = (texture_map[::4] != 0)

    dpg.set_value(f'map_{dpg.get_value('layer')}_texture', texture_map)

def mouse_pos_to_height_map_coords(coords):
    return map(int, coords)

def check_coords(x, y, w, h):
    return 0 <= x <= x + w <= dpg.get_item_width('map_child_window') and 0 <= y <= y + h <= dpg.get_item_height('map_child_window')

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

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

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

    return y1, y2, x1, x2

def mouse_down_callback():
    if not get_height_map_file_path():
        return
    if not dpg.is_item_focused('map_child_window'):
        return
    if not is_drawing():
        set_map_window_value('prev_coords', dpg.get_drawing_mouse_pos())
        set_map_window_value('drawing', True)
    else:
        if get_current_action() == 'erase' or get_current_action() == 'draw_rect':
            x, y = dpg.get_drawing_mouse_pos()
            px, py = get_prev_coords()
            w, h = abs(x - px), abs(y - py)
            x, y = min(x, px), min(y, py)
            if w > 0 and h > 0 and check_coords(x, y, w, h):
                dpg.set_item_pos('drawing_frame', [min(x, px), min(y, py)])
                dpg.set_item_width('drawing_frame', w)
                dpg.set_item_height('drawing_frame', h)
                dpg.show_item('drawing_frame')

def mouse_release_callback():
    if not get_height_map_file_path():
        return
    if not dpg.is_item_focused('map_child_window'):
        return

    dpg.hide_item('emission_values')

    coords = dpg.get_drawing_mouse_pos()

    if get_current_action() == 'erase':
        draw_rectangle(coords, 0)
    elif get_current_action() == 'draw_rect':
        layer = dpg.get_value('layer')
        if layer == 'roads':
            height = 1.
        else:
            height = dpg.get_value('height_input')
        draw_rectangle(coords, height)

    update_texture()

    set_map_window_value('drawing', False)

    dpg.hide_item('drawing_frame')

def mouse_click_callback():
    if not get_height_map_file_path():
        return
    if not get_config_file_path():
        return

    emission_points = get_emission_points()

    x, y = dpg.get_drawing_mouse_pos()

    is_pos_emission_point, n = is_mouse_pos_emission_point(x, y, emission_points)

    if is_pos_emission_point:
        dpg.set_item_width('emission_values', 300)
        dpg.set_item_height('emission_values', 300)
        dpg.set_item_pos('emission_values', dpg.get_drawing_mouse_pos())
        dpg.show_item('emission_values')
        dpg.set_value('emission_settings', f'value: {emission_points[n]['value']}\nbegin: {emission_points[n]['begin']}')
    else:
        if 0 <= x < dpg.get_item_width('map_child_window') and 0 <= y < dpg.get_item_height('map_child_window'):
            add_emission_point_and_update_ui(x, y)
            update_texture()

def draw_rectangle(coords, height):
    y1, y2, x1, x2 = get_rect(get_prev_coords(), coords)
    map_type = f'{dpg.get_value('layer')}_map'
    height_map = get_map_window_value(map_type)
    height_map[y1:y2, x1:x2] = height
    set_map_window_value(map_type, height_map)

def is_point_in_triangle(x1, y1, x2, y2, x3, y3, x, y):
    denominator = ((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3))
    a = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / denominator
    b = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) / denominator
    c = 1 - a - b
    return 0 <= a <= 1 and 0 <= b <= 1 and 0 <= c <= 1

def is_mouse_pos_emission_point(posx, posy, emission_points, side=30):
    h = (3 ** 0.5 / 2) * side
    for n in emission_points:
        x = emission_points[n]['xpos']
        y = emission_points[n]['ypos']
        x1, y1 = x, y - (2 / 3) * h
        x2, y2 = x + side / 2, y + (1 / 3) * h
        x3, y3 = x - side / 2, y + (1 / 3) * h

        if is_point_in_triangle(x1, y1, x2, y2, x3, y3, posx, posy):
            return True, n
    return False, 0

def draw_triangle(array, x, y, side=30, color=1.):
    
    h = (3 ** 0.5 / 2) * side

    x1, y1 = x, y - (2 / 3) * h
    x2, y2 = x + side / 2, y + (1 / 3) * h
    x3, y3 = x - side / 2, y + (1 / 3) * h

    for i in range(y - side, y + side):
        for j in range(x - side, x + side):
            if is_point_in_triangle(x1, y1, x2, y2, x3, y3, j, i):
                array[i, j] = color

    return array

def get_triangle_coords(x, y, side=30):
    h = (3 ** 0.5 / 2) * side

    x1, y1 = x, y - (2 / 3) * h
    x2, y2 = x + side / 2, y + (1 / 3) * h
    x3, y3 = x - side / 2, y + (1 / 3) * h

    return (x1, y1), (x2, y2), (x3, y3)