import os

import dearpygui.dearpygui as dpg
import tifffile
import numpy as np

from map_edit_constants import TREE_COLOR, ROAD_COLOR, BUILDING_COLOR, LAYER_TO_COLOR
from map_edit import dump_height_map, load_height_map, update_texture
from generator import LCZ
from paths import BASE_PATH
from utils import show_message, set_main_window_value, get_config, get_config_file_path, delete_item_and_clear_alias, delete_item_children_and_clear_aliases, set_map_window_value, get_map_window_value, get_height_map_file_path

def delete_emission_point_clb(s, a, u):
    n = dpg.get_item_user_data('emission_settings_window')
    prefix = f'{get_config_file_path()}.passive_tracers.tracer_{n}.point_emission'

    keys = ['value', 'begin', 'xpos', 'ypos', 'zpos', 'sx', 'sy', 'sz']

    config = get_config()

    for key in keys:
        path = f'passive_tracers.tracer_{n}.point_emission.{key}'
        del config[path]

    set_main_window_value('config', config)

    delete_item_children_and_clear_aliases(prefix)

    dpg.hide_item('emission_settings_window')

    tag = f'emission_point_{n}_triangle'

    dpg.delete_item(tag)

def set_emission_point_value_clb(s, value, u):
    n = dpg.get_item_user_data('emission_settings_window')

    key = s.split('_')[-1]

    path = f'{get_config_file_path()}.passive_tracers.tracer_{n}.point_emission.{key}'

    if dpg.does_item_exist(path):
        dpg.set_value(path, value)

    config = get_config()

    config[path].value = value

    set_main_window_value('config', config)

def clear_map():
    delete_item_and_clear_alias('map_buildings_texture')
    delete_item_and_clear_alias('map_trees_texture')
    delete_item_and_clear_alias('map_roads_texture')
    delete_item_children_and_clear_aliases('map_drawlist')
    settings = {
        'buildings_map': None,
        'trees_map': None,
        'roads_map': None,
        'height_map_file_path': None,
        'drawing': False,
        'prev_coords': None,
        'current_action': None,
        'max_height': 0
    }
    dpg.set_item_user_data('map_window', settings)

def map_window_on_close_clb(s, a, u):
    clear_map()

def construct_map_layers(w, h):
    dpg.set_item_width('map_child_window', w)
    dpg.set_item_height('map_child_window', h)

    dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag='map_buildings_texture', parent='textures')
    dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag='map_trees_texture', parent='textures')
    dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag='map_roads_texture', parent='textures')

    dpg.bind_item_theme('map_child_window', 'map_image_theme')
    dpg.add_drawlist(w, h, tag=f'map_drawlist', parent='map_child_window', pos=[0, 0])

    dpg.draw_image(f'map_buildings_texture', color=BUILDING_COLOR, tag=f'map_buildings_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')
    dpg.draw_image(f'map_trees_texture', color=TREE_COLOR, tag=f'map_trees_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')
    dpg.draw_image(f'map_roads_texture', color=ROAD_COLOR, tag=f'map_roads_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')

def map_open_layer_clb(s, a, u):
    height_map_file_path = a['file_path_name']

    layer = dpg.get_value('layer_radio_button')

    if height_map_file_path.endswith('txt'):
        try:
            height_map = load_height_map(height_map_file_path)
        except FileNotFoundError:
            show_message('no file found')
            return
        except Exception:
            show_message('bad file format')
            return
        max_height = np.max(height_map)
        height_map /= max_height
    else:
        height_map = tifffile.imread(height_map_file_path)
        max_height = 1

    h, w = height_map.shape

    delete_item_and_clear_alias(f'map_{layer}_texture')

    if dpg.does_alias_exist(f'map_{layer}_texture'):
        dpg.remove_alias(f'map_{layer}_texture')

    delete_item_and_clear_alias(f'map_{layer}_image')

    if dpg.does_alias_exist(f'map_{layer}_image'):
        dpg.remove_alias(f'map_{layer}_image')

    set_map_window_value(f'{layer}_map', height_map)

    dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag=f'map_{layer}_texture', parent='textures')
    
    dpg.draw_image(f'map_{layer}_texture', color=LAYER_TO_COLOR[layer], tag=f'map_{layer}_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')

    dpg.set_value('layer', layer)

    update_texture()

def map_open_clb(s, a, u):
    height_map_file_path = a['file_path_name']

    if height_map_file_path.endswith('txt'):
        try:
            height_map = load_height_map(height_map_file_path)
        except FileNotFoundError:
            show_message('no file found')
            return
        except Exception:
            show_message('bad file format')
            return
        max_height = np.max(height_map)
        height_map /= max_height
    else:
        height_map = tifffile.imread(height_map_file_path)
        max_height = 1

    h, w = height_map.shape

    clear_map()

    set_map_window_value('buildings_map', height_map)
    set_map_window_value('roads_map', np.zeros((h, w)))
    set_map_window_value('trees_map', np.zeros((h, w)))
    set_map_window_value('height_map_file_path', height_map_file_path)
    set_map_window_value('max_height', max_height)

    construct_map_layers(w, h)

    dpg.set_value('layer', 'buildings')
    
    update_texture()

    dpg.show_item('map_window')

def generate_map_clb(s, a, u):
    height_map = LCZ(config_path=os.path.join(BASE_PATH, 'configs', f'{s}.json')).to_height_map(dtype=np.float64)

    max_height = np.max(height_map)
    height_map /= max_height

    h, w = height_map.shape

    clear_map()

    set_map_window_value('buildings_map', height_map)
    set_map_window_value('roads_map', np.zeros((h, w)))
    set_map_window_value('trees_map', np.zeros((h, w)))
    set_map_window_value('height_map_file_path', 'map.txt')
    set_map_window_value('max_height', max_height)

    construct_map_layers(w, h)

    dpg.set_value('layer', 'buildings')

    update_texture()

    dpg.show_item('map_window')

def save_map(file_path):
    if file_path.endswith('.tif') or file_path.endswith('.tiff'):
        with TiffWriter(file_path) as tif:
            tif.write(get_map_window_value('buildings_map'))
            tif.write(get_map_window_value('roads_map'))
            tif.write(get_map_window_value('trees_map'))
    else:
        dump_height_map(get_map_window_value('buildings_map'), file_path)

def map_save_clb(s, a, u):
    file_path = get_height_map_file_path()
    save_map(file_path)
    show_message('file saved successfully:)')

def map_save_as_clb(s, a, u):
    file_path = a['file_path_name']
    save_map(file_path)
    show_message('file saved successfully:)')

def open_map_save_as_dialog_clb(s, a, u):
    dpg.show_item('map_save_as')

def open_map_open_dialog_clb(s, a, u):
    dpg.show_item('map_open')

def open_map_open_layer_dialog_clb(s, a, u):
    dpg.show_item('map_open_layer')

def set_action_clb(s, a, u):
    set_map_window_value('current_action', s)

def set_action_none_clb(s, a, u):
    set_map_window_value('current_action', None)