# -*- coding:utf-8 -*-
# title           :场景用功能库
# description     :场景用功能库
# author          :Python超人
# date            :2023-02-11
# link            :https://gitcode.net/pythoncr/
# python_version  :3.8
# ==============================================================================
import matplotlib.pyplot as plt
from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, SECONDS_PER_HALF_DAY
from common.system import System
from simulators.ursina.ursina_config import UrsinaConfig
from simulators.ursina.ursina_event import UrsinaEvent


def mayavi_run(bodies, dt=SECONDS_PER_WEEK,
               view_azimuth=0, view_distance='auto', view_focalpoint='auto',
               bgcolor=(1 / 255, 1 / 255, 30 / 255)):
    """
    用 mayavi 查看运行效果
    :param bodies: 天体
    :param dt: 单位：秒，按时间差进行演变，值越小越精确，但演变速度会慢。
    :param view_azimuth: 观测方位角，可选，float类型（以度为单位，0-360），用x轴投影到x-y平面上的球体上的位置矢量所对的角度。
    :param view_distance: 观测距离，可选，float类型 or 'auto',一个正浮点数，表示距放置相机的焦点的距离。
    :param view_focalpoint: 观测焦点，可选，类型为一个由3个浮点数组成的数组 or 'auto'，，代表观测相机的焦点
    :param bgcolor:
    :return:
    """
    from mayavi import mlab
    from simulators.mayavi_simulator import MayaviSimulator
    # 宇宙背景色
    mlab.figure(bgcolor=bgcolor, size=(1440, 810))
    body_sys = System(bodies)
    simulator = MayaviSimulator(body_sys)
    simulator.run(dt)
    # azimuth:
    #    观测方位角，可选，float类型（以度为单位，0-360），用x轴投影到x-y平面上的球体上的位置矢量所对的角度。
    # elevation:
    #    观测天顶角，可选，float类型（以度为单位，0-180）, 位置向量和z轴所对的角度。
    # distance:
    #    观测距离，可选，float类型 or 'auto',一个正浮点数，表示距放置相机的焦点的距离。
    #    Mayavi 3.4.0中的新功能：'auto' 使得距离为观察所有对象的最佳位置。
    # focalpoint:
    #    观测焦点，可选，类型为一个由3个浮点数组成的数组 or 'auto'，，代表观测相机的焦点
    #    Mayavi 3.4.0中的新功能：'auto'，则焦点位于场景中所有对象的中心。
    # roll:
    #    控制滚动，可选，float类型，即摄影机围绕其轴的旋转
    # reset_roll:
    #    布尔值，可选。如果为True，且未指定“滚动”，则重置相机的滚动方向。
    # figure:
    #    要操作的Mayavi图形。如果为 None，则使用当前图形。
    mlab.view(azimuth=view_azimuth, distance=view_distance, focalpoint=view_focalpoint)
    # mlab.view(azimuth=-45, elevation=45, distance=100e8 * 2 * 2 * 4 * 4, focalpoint=[5e10, 5e10, 5e9])
    mlab.show()


def ursina_run(bodies,
               dt=SECONDS_PER_HALF_DAY,
               position=(0, 0, 0),
               # view_azimuth=0,
               light=True,
               cosmic_bg=None,
               bg_music=None,
               show_grid=True,
               show_trail=False,
               show_name=False,
               save_as_json=None):
    """

    :param bodies: 天体
    :param dt: 单位：秒，按时间差进行演变，值越小越精确，但演变速度会慢。
    :param position: 摄像头位置
    :param view_azimuth: 摄像头观测方位角，可选，float类型（以度为单位，0-360）
    :param light: 使用灯光效果
    :param cosmic_bg: 宇宙背景图片
    :param show_grid: 是否显示空间网格
    :param save_as_json: 将所有天体的信息保存为 json 文件
    :param ignore_mass: 忽略所有天体的引力
    :return:
    """

    from simulators.ursina_simulator import UrsinaSimulator, UrsinaPlayer
    from ursina import application, Sequence, camera, held_keys, time, clamp, Entity, Text, color
    from ursina.prefabs.first_person_controller import FirstPersonController
    body_sys = System(bodies)

    if show_name:
        for body in body_sys.bodies:
            body.show_name = True

    if save_as_json is not None:
        try:
            body_sys.save_to_json(save_as_json, {"dt": dt, "position": position,
                                                 "show_trail": show_trail, "show_name": show_name})
            print(f"{save_as_json} 文件生成成功！")
        except Exception as e:
            print(f"{save_as_json} 文件生成失败！" + str(e))
        return
    simulator = UrsinaSimulator(body_sys)
    view_azimuth = 0  # 暂时未用
    player = UrsinaPlayer(position, view_azimuth, simulator.ursina_views)

    # # player = FirstPersonController(model='cube', y=-1e20, color=color.orange, origin_y=-5000, speed=8)
    # # player.on_disable()
    # # player.position = position
    #
    # player = FirstPersonController()
    # cube = Entity(model='cube', color=color.red, scale=2)
    # player.parent = cube  # 设置 FirstPersonController 的父实体为 cube
    # cube.position = position  # 修改父实体的位置，从而间接地修改 FirstPersonController 的位置

    # # 创建一个实体（在屏幕中央）和一个摄像机
    # TODO: 未使用
    # entity = Entity(model='cube', position=(0, 0, 5), scale=2)
    # camera = Camera()
    #
    # # 设置初始的 FOV 值（默认值为 90）
    # camera.fov = 60
    #
    # # 创建一个用于显示当前 FOV 值的文本
    # fov_text = Text(text=f'FOV: {camera.fov}', position=(-0.5, 0.4), scale=2)
    # # 每一帧更新摄像机 FOV 值
    # def update():
    #     # 通过鼠标滚轮来调整 FOV 值
    #     camera.fov -= held_keys['scroll'] * 10 * time.dt
    #     # 限制 FOV 值的范围（1 到 120 之间）
    #     camera.fov = clamp(camera.fov, 1, 120)
    #     # 更新文本内容
    #     fov_text.text = f'FOV: {camera.fov:.2f}'  # 保留两位小数
    #
    #     # 将摄像机移到实体旁边，并对着它
    #     camera.position = entity.position + (0, 0, -5)
    #     camera.look_at(entity.position)

    def callback_update():
        UrsinaEvent.on_application_run()
        for ursina_view in simulator.ursina_views:
            simulator.check_and_evolve()
            if ursina_view.appeared:
                ursina_view.update()
        # print('....')

    import sys
    sys.modules["__main__"].update = callback_update
    if show_trail:
        UrsinaConfig.show_trail = show_trail
    simulator.run(dt, light=light, cosmic_bg=cosmic_bg, show_grid=show_grid, bg_music=bg_music)


def mpl_run(bodies, dt=SECONDS_PER_WEEK, gif_file_name=None, gif_max_frame=200):
    """

    :param bodies: 天体
    :param dt: 单位：秒，按时间差进行演变，值越小越精确，但演变速度会慢。
    :param gif_file_name: 导出的 gif 文件名，如果为空，则显示动画
    :return:
    """
    from simulators.mpl_simulator import MplSimulator
    body_sys = System(bodies)
    simulator = MplSimulator(body_sys)

    simulator.run(dt, gif_file_name=gif_file_name, gif_max_frame=gif_max_frame)


COSMIC_BG_COLOR = "#002563"
COSMIC_FORE_COLOR = "white"


def create_fig_ax(styles={}):
    bg_color = styles["bg_color"] if "bg_color" in styles else COSMIC_BG_COLOR
    fore_color = styles["fore_color"] if "fore_color" in styles else COSMIC_FORE_COLOR
    if bg_color is None:
        fig = plt.figure('天体模拟运行效果', figsize=(20, 12))
    else:
        fig = plt.figure('天体模拟运行效果', figsize=(20, 12), facecolor=bg_color)
    ax = fig.gca(projection="3d")

    return fig, ax


if __name__ == '__main__':
    from bodies import Sun, Earth

    """
    太阳、地球
    """
    bodies = [
        Sun(size_scale=1.2e2),  # 太阳放大 120 倍
        Earth(size_scale=4e3, distance_scale=1),  # 地球放大 4000 倍，距离保持不变
    ]
    # mpl_run(bodies, SECONDS_PER_WEEK)
    ursina_run(bodies, SECONDS_PER_WEEK)
