using System.Text.Json;
using DoomDeathmatch.Component.UI;
using DoomDeathmatch.Component.Util;
using DoomDeathmatch.Scene.Play;
using DoomDeathmatch.Script.Score;
using DoomDeathmatch.Script.UI;
using Engine.Graphics.Pipeline;
using Engine.Scene;
using Engine.Scene.Component.BuiltIn;
using Engine.Scene.Component.BuiltIn.Renderer;
using Engine.Util;
using OpenTK.Mathematics;

namespace DoomDeathmatch.Scene.Main;

public static class MainScene
{
  public static Engine.Scene.Scene Create()
  {
    var scene = new Engine.Scene.Scene();

    var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene);

    var (uiContainerObject, uiContainer) =
      UiUtil.CreateBackgroundUi(scene, new UiContainerComponent { Camera = camera });

    var (logoObject, logoUi) = UiUtil.CreateLogoUi(scene, uiContainer);
    logoUi.Offset = new Vector2(0, 3f);
    scene.AddChild(uiContainerObject, logoObject);

    var menuController = new MenuControllerComponent();
    var menuControllerObject = GameObjectUtil.CreateGameObject(scene, [
      menuController
    ]);

    var mainMenu = CreateMainMenu(scene, uiContainer, menuController);
    menuController.AddMenuItem("main", mainMenu);

    var leadersMenu = CreateLeadersMenu(scene, uiContainer, menuController);
    leadersMenu.IsEnabled = false;
    menuController.AddMenuItem("leaders", leadersMenu);

    var rulesMenu = CreateRulesMenu(scene, uiContainer, menuController);
    rulesMenu.IsEnabled = false;
    menuController.AddMenuItem("rules", rulesMenu);

    scene.AddChild(uiContainerObject, mainMenu);
    scene.AddChild(uiContainerObject, leadersMenu);
    scene.AddChild(uiContainerObject, rulesMenu);

    return scene;
  }

  private static GameObject CreateMainMenu(Engine.Scene.Scene parScene,
    UiContainerComponent parUiContainer, MenuControllerComponent parMenuController)
  {
    var parentObject = GameObjectUtil.CreateGameObject(parScene);

    var (playUiObject, playUi, _) =
      UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(), "Играть");

    var (leadersUiObject, leadersUi, _) =
      UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(), "Лидеры");

    var (rulesUiObject, rulesUi, _) =
      UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(), "Правила");

    var (exitUiObject, exitUi, _) =
      UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(), "Выход");

    var (stackObject, stack) = UiUtil.CreateStackUi(parScene,
      new StackComponent
      {
        Offset = new Vector2(0, -1f), Container = parUiContainer, Children = { playUi, leadersUi, rulesUi, exitUi }
      });
    stackObject.Transform.Size.Xy = new Vector2(1f, 6f);

    playUi.OnClick += _ => EngineUtil.SceneManager.TransitionTo(PlayScene.Create);
    leadersUi.OnClick += _ => parMenuController.SelectMenuItem("leaders");
    rulesUi.OnClick += _ => parMenuController.SelectMenuItem("rules");
    exitUi.OnClick += _ => EngineUtil.Close();

    var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene,
      new SelectorComponent { Children = { playUi, leadersUi, rulesUi, exitUi } });

    parScene.AddChild(parentObject, selectorObject);
    parScene.AddChild(parentObject, stackObject);

    parScene.AddChild(stackObject, playUiObject);
    parScene.AddChild(stackObject, leadersUiObject);
    parScene.AddChild(stackObject, rulesUiObject);
    parScene.AddChild(stackObject, exitUiObject);

    return parentObject;
  }

  private static GameObject CreateLeadersMenu(Engine.Scene.Scene parScene,
    UiContainerComponent parUiContainer, MenuControllerComponent parMenuController)
  {
    var parentObject = GameObjectUtil.CreateGameObject(parScene);

    var (backUiObject, backUi, _) = UiUtil.CreateTextUi(parScene, parUiContainer,
      UiUtil.GetDoomFont(), "Назад");
    backUi.OnClick += _ => parMenuController.SelectMenuItem("main");

    var (stackObject, stack) = UiUtil.CreateStackUi(parScene,
      new StackComponent { Offset = new Vector2(0, -1.5f), Container = parUiContainer, Children = { } });
    stackObject.Transform.Size.Xy = new Vector2(1f, 6f);

    var leadersTable = CreateLeadersTable(parScene, parUiContainer, EngineUtil.DataFolder);
    foreach (var (rowObject, rowUi) in leadersTable)
    {
      stack.Children.Add(rowUi);
      parScene.AddChild(stackObject, rowObject);
    }

    stack.Children.Add(backUi);

    var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene, new SelectorComponent { Children = { backUi } });

    parScene.AddChild(parentObject, selectorObject);
    parScene.AddChild(parentObject, stackObject);
    parScene.AddChild(stackObject, backUiObject);

    return parentObject;
  }

  private static List<(GameObject, UiComponent)> CreateLeadersTable(Engine.Scene.Scene parScene,
    UiContainerComponent parUiContainer, string parDataFolder)
  {
    var leadersTableList =
      new List<(GameObject, UiComponent)> { CreateLeadersRow(parScene, parUiContainer, "Имя", "Очки") };

    var leadersTable = ScoreTable.LoadOrCreate(Path.Combine(parDataFolder, "leaders.json"));

    var rows = 0;
    foreach (var row in leadersTable.Rows)
    {
      leadersTableList.Add(CreateLeadersRow(parScene, parUiContainer, row.Name, row.Score.ToString()));
      if (++rows >= 5)
        break;
    }

    return leadersTableList;
  }

  private static (GameObject, UiComponent) CreateLeadersRow(Engine.Scene.Scene parScene,
    UiContainerComponent parUiContainer, string parName, string parScore)
  {
    var uiComponent = new UiContainerComponent { Container = parUiContainer };

    var rowObject = GameObjectUtil.CreateGameObject(parScene,
      new Transform { Size = new Vector3(5, 8, 1) }, [
        uiComponent
      ]);

    var (nameUiObject, nameUi, _) =
      UiUtil.CreateTextUi(parScene, uiComponent, UiUtil.GetDoomFont(), parName);
    nameUi.Anchor = Anchor.CenterLeft;
    nameUi.Center = Anchor.Center;

    var (scoreUiObject, scoreUi, _) =
      UiUtil.CreateTextUi(parScene, uiComponent, UiUtil.GetDoomFont(), parScore);
    scoreUi.Anchor = Anchor.CenterRight;
    scoreUi.Center = Anchor.Center;

    parScene.AddChild(rowObject, nameUiObject);
    parScene.AddChild(rowObject, scoreUiObject);

    return (rowObject, uiComponent);
  }

  private static GameObject CreateRulesMenu(Engine.Scene.Scene parScene,
    UiContainerComponent parUiContainer, MenuControllerComponent parMenuController)
  {
    var parentObject = GameObjectUtil.CreateGameObject(parScene);

    var (backUiObject, backUi, _) = UiUtil.CreateTextUi(parScene, parUiContainer,
      UiUtil.GetDoomFont(), "Назад");
    backUi.OnClick += _ => parMenuController.SelectMenuItem("main");

    var (rulesObject, rulesUi, _) = UiUtil.CreateTextUi(parScene, parUiContainer,
      UiUtil.GetDoomFont(), "Правила");

    var (stackObject, stack) = UiUtil.CreateStackUi(parScene,
      new StackComponent { Offset = new Vector2(0, -1f), Container = parUiContainer, Children = { rulesUi, backUi } });
    stackObject.Transform.Size.Xy = new Vector2(1f, 6f);

    var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene, new SelectorComponent { Children = { backUi } });

    parScene.AddChild(parentObject, selectorObject);

    parScene.AddChild(parentObject, stackObject);

    parScene.AddChild(stackObject, rulesObject);
    parScene.AddChild(stackObject, backUiObject);

    return parentObject;
  }
}