# -*- coding:utf-8 -*-
# title           :ursina天体运行模拟器UI控制
# description     :ursina天体运行模拟器UI控制
# author          :Python超人
# date            :2023-02-11
# link            :https://gitcode.net/pythoncr/
# python_version  :3.8
# ==============================================================================
from ursina import Ursina, window, Entity, Grid, Mesh, camera, Text, application, color, mouse, Vec2, Vec3, \
    load_texture, held_keys, Button, ButtonList, destroy, scene, distance, Sequence, Wait, Func
from ursina.prefabs.first_person_controller import FirstPersonController
from common.consts import SECONDS_PER_HOUR, SECONDS_PER_HALF_DAY, \
    SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH, SECONDS_PER_YEAR
from common.consts import AU
from simulators.ursina.ui.ui_panel import UiPanel
from simulators.ursina.ui_component import UiSlider, SwithButton, UiButton, Buttons
from simulators.ursina.ursina_config import UrsinaConfig
from simulators.ursina.ursina_event import UrsinaEvent
from ursina import WindowPanel, InputField, Button, Slider, ButtonGroup, Panel, invoke
from simulators.ursina.ui.event_handler import EventHandler


class ControlHandler(EventHandler):
    """
    控制面板事件处理类
    """

    def handler_input_init(self):
        """
        输入事件初始化
        @return:
        """
        self.settings_handler = Entity(ignore_paused=True)
        self.settings_handler.input = self.settings_handler_input
        key_info_str = "方位控制[键盘QWEASD]+[鼠标右键]，按[空格]更多控制"
        key_info = Text(text=key_info_str, font=UrsinaConfig.CN_FONT, position=(-1, 0.5), origin=(-1, 1),
                        background=True)

    def sec_per_time_switch_changed(self):
        """
        按钮组("默认", "天", "周", "月", "年", "十年", "百年") 点击
        @return:
        """
        if self.ui.sec_per_time_switch.value == "天":
            UrsinaConfig.seconds_per = SECONDS_PER_DAY
        elif self.ui.sec_per_time_switch.value == "周":
            UrsinaConfig.seconds_per = SECONDS_PER_WEEK
        elif self.ui.sec_per_time_switch.value == "月":
            UrsinaConfig.seconds_per = SECONDS_PER_MONTH
        elif self.ui.sec_per_time_switch.value == "年":
            UrsinaConfig.seconds_per = SECONDS_PER_YEAR
        elif self.ui.sec_per_time_switch.value == "十年":
            UrsinaConfig.seconds_per = SECONDS_PER_YEAR * 10
        elif self.ui.sec_per_time_switch.value == "百年":
            UrsinaConfig.seconds_per = SECONDS_PER_YEAR * 100
        else:
            UrsinaConfig.seconds_per = 0  # 默认

    def on_off_trail_changed(self):
        """
        拖尾开关点击
        @return:
        """
        if self.ui.on_off_trail.value == self.ui.trail_button_text:
            UrsinaConfig.show_trail = True
        else:
            UrsinaConfig.show_trail = False

    def move_camera_to_entity2(self, camera_pos: Vec3, entity_pos: Vec3, _distance: float) -> Vec3:
        # 计算摄像机到实体的向量
        direction = entity_pos - camera_pos
        # 计算当前距离
        current_distance = direction.length()
        # 如果当前距离已经小于等于要求的距离，则直接返回实体坐标
        if current_distance <= _distance:
            return camera_pos
        # 计算需要移动的距离
        _distance = current_distance - _distance
        # 根据需要移动的距离计算移动向量
        move_vector = direction.normalized() * _distance
        # 返回摄像机移动后的坐标
        return camera_pos + move_vector

    def move_camera_to_entity(self, entity, d):
        camera.position = entity.position  # - Vec3(0, 0, d)  # 设置摄像机位置
        camera.world_position = entity.position
        forward = camera.forward

    def search_bodies_button_list_click(self, item):
        """

        @param item:
        @return:
        """
        if item is not None:
            # TODO: 先找到位置，确定摄像机的位置
            try:
                d = item.planet.scale_x * 20
                self.move_camera_to_entity(item.planet, d)
            except Exception as e:
                self.ui.show_message(f"{item}飞不见了")

        self.search_bodies_button_list_close()

    def search_bodies_button_list_close(self):
        if hasattr(self, "search_bodies_button_list"):
            self.search_bodies_button_list.enabled = False
            destroy(self.search_bodies_button_list)

    def on_searching_bodies_click(self):
        results = UrsinaEvent.on_searching_bodies()
        if len(results) > 0:
            sub_name, bodies = results[0]
            if len(bodies) == 0:
                self.ui.show_message("天体都飞不见了，请重新运行。")
                return

            button_dict = {"[关闭]        == 寻找天体 ==": lambda: self.search_bodies_button_list_click(None)}
            camera = scene.camera
            for body in bodies:
                def callback_action(b=body):
                    self.search_bodies_button_list_click(b)

                if body.appeared:
                    distance_to_entity = distance(body.planet, camera)
                    d = distance_to_entity / UrsinaConfig.SCALE_FACTOR / AU
                    name = f"{body.name}\t距离：{d:.4f}天文单位"
                    button_dict[name] = callback_action
                else:
                    if hasattr(self, "search_bodies_button_list"):
                        self.search_bodies_button_list_close()
                    name = f"{body.name}\t距离太远，找不到了"
                    button_dict[name] = lambda: self.search_bodies_button_list_click(None)

            if hasattr(self, "search_bodies_button_list"):
                self.search_bodies_button_list_close()

            self.search_bodies_button_list = ButtonList(button_dict,
                                                        font=UrsinaConfig.CN_FONT,
                                                        button_height=1.5,
                                                        ignore_paused=True)

    def on_reset_button_click(self):
        paused = application.paused
        if paused:  # 如果是暂停状态，先不暂停，等重新开始后再暂停
            application.paused = False
        UrsinaEvent.on_reset()
        if paused:
            def application_paused():
                application.paused = True

            UrsinaEvent.on_application_run_callback_subscription(application_paused)

    # def on_buttons_changed(self):
    #     if self.ui.buttons.value == "寻找":
    #         self.on_searching_bodies_click()
    #     elif self.ui.buttons.value == "重启":
    #         self.on_reset_button_click()

    def on_off_switch_changed(self):
        if self.ui.on_off_switch.value == self.ui.pause_button_text:
            self.ui.on_off_switch.selected_color = color.green
            application.paused = True
            for c in self.ui.children:
                if not c.ignore_paused:
                    # c.enabled = True
                    c.disabled = False
        else:
            self.ui.on_off_switch.selected_color = color.red
            application.paused = False
            for c in self.ui.children:
                if not c.ignore_paused:
                    # c.enabled = True
                    c.disabled = False

    def on_slider_trail_length_changed(self):
        UrsinaConfig.trail_length = int(self.ui.slider_trail_length.value)

    def on_slider_control_speed_changed(self):
        application.time_scale = self.ui.slider_control_speed_factor.value

    def on_slider_body_spin_changed(self):
        UrsinaConfig.body_spin_factor = self.ui.slider_body_spin_factor.value

    def on_slider_body_size_changed(self):
        UrsinaConfig.body_size_factor = self.ui.slider_body_size_factor.value

    def on_slider_run_speed_changed(self):
        UrsinaConfig.run_speed_factor = self.ui.slider_run_speed_factor.value

    def settings_handler_input(self, key):
        """

        @param key:
        @return:
        """
        import sys
        if key == "escape":
            sys.exit()
        # print(key)
        elif key == 'space':
            self.ui.enabled = not self.ui.enabled
        elif key == 'left mouse down':
            print(key)
        elif key == 'y':  # 寻找天体
            if hasattr(self, "search_bodies_button_list"):
                if self.search_bodies_button_list.enabled:
                    self.search_bodies_button_list_close()
                    return
            self.on_searching_bodies_click()
        elif key == 'o':  # 重新开始
            self.on_reset_button_click()
        elif key == 'i':  # 拖尾开关
            if self.ui.on_off_trail.value == self.ui.trail_button_text:
                self.ui.on_off_trail.value = self.ui.no_trail_button_text
            else:
                self.ui.on_off_trail.value = self.ui.trail_button_text
            self.on_off_trail_changed()
        elif key == 'p':  # 开始、暂停
            if self.ui.on_off_switch.value == self.ui.pause_button_text:
                self.ui.on_off_switch.value = self.ui.start_button_text
            else:
                self.ui.on_off_switch.value = self.ui.pause_button_text
            self.on_off_switch_changed()
        elif key == '+' or key == "= up":
            self.slider_increase(self.ui.slider_run_speed_factor)
        elif key == '-' or key == "- up":
            self.slider_decrease(self.ui.slider_run_speed_factor)
        elif key == 'n':
            import math
            # min=0.01, max=20
            #   # ', up' <  > '. up'   n    m
            self.ui.slider_control_speed_factor.current_step = self.ui.slider_control_speed_factor.value/2
            self.slider_decrease(self.ui.slider_control_speed_factor, self.ui.slider_control_speed_factor.current_step)

            print(self.ui.slider_control_speed_factor.current_step)
        elif key == 'm':
            self.ui.slider_control_speed_factor.current_step = self.ui.slider_control_speed_factor.value
            self.slider_increase(self.ui.slider_control_speed_factor, self.ui.slider_control_speed_factor.current_step)
            print(self.ui.slider_control_speed_factor.current_step)

    def slider_increase(self, slider, step=50):
        """

        @param slider:
        @param step:
        @return:
        """
        run_speed_factor = slider.value + step
        if run_speed_factor > slider.max:
            run_speed_factor = slider.max
        slider.value = run_speed_factor
        slider.knob.drop()

    def slider_decrease(self, slider, step=50):
        """

        @param slider:
        @param step:
        @return:
        """
        value = slider.value - step
        if value < slider.min:
            value = slider.min
        slider.value = value
        slider.knob.drop()
