using DoomDeathmatch.Component.UI;
using Engine.Asset.Font;
using Engine.Graphics.Pipeline;
using Engine.Graphics.Texture;
using Engine.Input;
using Engine.Scene;
using Engine.Scene.Component.BuiltIn;
using Engine.Scene.Component.BuiltIn.Renderer;
using OpenTK.Mathematics;

namespace DoomDeathmatch;

public static class UiUtil
{
  public static Font GetDoomFont(Engine.Engine parEngine)
  {
    return parEngine.AssetResourceManager.Load<Font>("font/doom");
  }

  public static (GameObject, OrthographicCamera) CreateOrthographicCamera(Engine.Scene.Scene parScene,
    RenderLayer? parRenderLayer = null)
  {
    OrthographicCamera camera;
    var cameraObject = GameObjectUtil.CreateGameObject(parScene, [
      camera = new OrthographicCamera { RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT }
    ]);

    return (cameraObject, camera);
  }

  public static (GameObject, PerspectiveCamera) CreatePerspectiveCamera(Engine.Scene.Scene parScene,
    RenderLayer? parRenderLayer = null)
  {
    PerspectiveCamera camera;
    var cameraObject = GameObjectUtil.CreateGameObject(parScene, [
      camera = new PerspectiveCamera { RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT }
    ]);

    return (cameraObject, camera);
  }

  public static (GameObject, UiContainerComponent, (GameObject, TextRenderer)) CreateTextUi(Engine.Scene.Scene parScene,
    UiContainerComponent parContainer,
    Font parFont, string parText, TextAlignComponent.Align parAlign = TextAlignComponent.Align.Center,
    RenderLayer? parRenderLayer = null)
  {
    var size = parFont.Measure(parText);
    var outerObject = new GameObject
    {
      Transform = { Size = new Vector3(size.X, size.Y, 1f), Translation = new Vector3(0, 0, -1) }
    };
    var uiComponent = new UiContainerComponent { Container = parContainer };
    outerObject.AddComponent(uiComponent);
    outerObject.AddComponent(new Box2DRenderer
    {
      Color = new Vector4(0, 0, 1, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT
    });

    var innerObject = new GameObject { Transform = { Translation = new Vector3(0, 0, -1) } };
    // var innerUiComponent = new UiComponent { Container = uiComponent };
    // innerObject.AddComponent(innerUiComponent);
    var innerTextRenderer = new TextRenderer
    {
      Font = parFont, Text = parText, RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT
    };
    innerObject.AddComponent(innerTextRenderer);
    innerObject.AddComponent(new TextAlignComponent { Alignment = parAlign });

    parScene.Add(outerObject);
    parScene.AddChild(outerObject, innerObject);

    return (outerObject, uiComponent, (innerObject, innerTextRenderer));
  }

  public static (GameObject, UiContainerComponent) CreateContainerUi(Engine.Scene.Scene parScene,
    UiContainerComponent parUiContainerComponent)
  {
    var uiContainerObject = new GameObject();
    uiContainerObject.AddComponent(parUiContainerComponent);

    parScene.Add(uiContainerObject);

    return (uiContainerObject, parUiContainerComponent);
  }

  public static (GameObject, UiContainerComponent) CreateBackgroundUi(Engine.Scene.Scene parScene,
    UiContainerComponent parUiContainerComponent, Vector4? parColor = null,
    RenderLayer? parRenderLayer = null)
  {
    var (uiContainerObject, uiContainer) = CreateContainerUi(parScene, parUiContainerComponent);
    uiContainerObject.AddComponent(new Box2DRenderer
    {
      Color = parColor ?? new Vector4(0.1f, 0.1f, 0.1f, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT
    });

    return (uiContainerObject, uiContainer);
  }

  public static (GameObject, UiComponent) CreateLogoUi(Engine.Engine parEngine, Engine.Scene.Scene parScene,
    UiContainerComponent parContainer, RenderLayer? parRenderLayer = null)
  {
    UiComponent uiComponent;
    var logoObject = GameObjectUtil.CreateGameObject(parScene,
      new Transform
      {
        Translation = new Vector3(0, 0, -10), Scale = new Vector3(3), Size = new Vector3(1.6385869565f, 1f, 1f)
      }, [
        new Box2DRenderer
        {
          Texture = parEngine.AssetResourceManager.Load<Texture>("texture/doom_logo.png"),
          RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT
        },
        uiComponent = new UiComponent { Container = parContainer, Anchor = Anchor.Center }
      ]
    );

    return (logoObject, uiComponent);
  }

  public static (GameObject, (UiComponent, Box2DRenderer)) CreateSpriteUi(Engine.Scene.Scene parScene,
    UiContainerComponent parContainer,
    Texture? parTexture, RenderLayer? parRenderLayer = null)
  {
    var spriteObject = new GameObject();
    var spriteComponent = new Box2DRenderer
    {
      Texture = parTexture, RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT
    };
    spriteObject.AddComponent(spriteComponent);
    var uiComponent = new UiContainerComponent { Container = parContainer };
    spriteObject.AddComponent(uiComponent);

    return (spriteObject, (uiComponent, spriteComponent));
  }

  public static (GameObject, StackComponent) CreateStackUi(Engine.Scene.Scene parScene,
    StackComponent parStackComponent, RenderLayer? parRenderLayer = null)
  {
    foreach (var child in parStackComponent.Children)
      child.Container = parStackComponent;

    var stackObject = new GameObject { Transform = { Translation = new Vector3(0, 0, -1) } };
    stackObject.AddComponent(parStackComponent);
    // stackObject.AddComponent(new Box2DRenderer { Color = new Vector4(1, 0, 0, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT });

    parScene.Add(stackObject);

    return (stackObject, parStackComponent);
  }

  public static (GameObject, SelectorComponent) CreateSelectorUi(Engine.Scene.Scene parScene,
    SelectorComponent parSelectorComponent, RenderLayer? parRenderLayer = null)
  {
    var selectorObject = new GameObject { Transform = { Translation = new Vector3(0, 0, -1) } };
    selectorObject.AddComponent(parSelectorComponent);
    var innerSelectorObject = new GameObject
    {
      Transform = { Translation = new Vector3(-0.5f, 0, -1), Size = new Vector3(0.25f, 0.5f, 1f) }
    };
    innerSelectorObject.AddComponent(new Box2DRenderer
    {
      Color = new Vector4(1, 1, 1, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT
    });

    parScene.Add(selectorObject);
    parScene.AddChild(selectorObject, innerSelectorObject);

    return (selectorObject, parSelectorComponent);
  }
}