import dearpygui.dearpygui as dpg

import numpy as np

from utils import get_map_window_value, get_config_file_path, is_drawing, get_current_action, set_map_window_value, get_emission_points, get_prev_coords, get_height_map_file_path
from map_edit_constants import EMISSION_POINT_COLOR
from dynamic_ui import add_emission_point_and_update_ui

def load_height_map(file_path):
    with open(file_path, "r", encoding='utf-8') 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
        data = height_map * get_map_window_value('max_height')
        file.write(f"{w} {h}\n")
        for row in data:
            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)
            tag = f'emission_point_{n}_triangle'
            if not dpg.does_item_exist(tag):
                dpg.draw_polygon(coords, color=EMISSION_POINT_COLOR, fill=(255, 0, 0, 255), tag=tag, parent='map_drawlist', thickness=0)

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

    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

    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

    if dpg.is_item_visible('emission_settings_window'):
        dpg.hide_item('emission_settings_window')
        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:
        for key in emission_points[n]:
            dpg.set_value(f'emission_point_{key}', emission_points[n][key])
        dpg.set_item_user_data('emission_settings_window', n)
        dpg.set_item_pos('emission_settings_window', dpg.get_drawing_mouse_pos())
        dpg.show_item('emission_settings_window')
    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 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)