﻿using Nemesis;
using Nemesis.Rendering;
using Nemesis.Rendering.Animation;
using Nemesis.Rendering.OpenGL.Texture;
using NemesisGame.Level;
using NemesisGame.Rendering.OpenGL;
using OpenTK;

namespace NemesisGame.Player
{
    public sealed class HeroLoader
    {
        private readonly TextureRendererFactory spriteRenderer;
        private readonly HeroTextures heroTextures;
        private readonly ILevel level;

        public HeroLoader(TextureRendererFactory spriteRenderer, HeroTextures heroTextures, ILevel level)
        {
            this.spriteRenderer = spriteRenderer;
            this.heroTextures = heroTextures;
            this.level = level;
        }

        public ICharacter LoadIntoGame(IGame game)
        {
            var hero = Create();
            game.AddObject(hero);
            return hero;
        }

        private ICharacter Create()
        {
            var hero = new Character(level, Vector3.Zero, 1.2f);

            AddHeroIdlePoseRenderer(hero);
            AddHeroJumpingPoseRenderer(hero);
            AddHeroFallingPoseRenderer(hero);
            AddHeroWalkingPoseRenderer(hero);

            return hero;
        }

        private void AddHeroIdlePoseRenderer(ICharacter hero)
        {
            var idleTileset = CreateTileset(heroTextures.HeroIdle, "Content/idle_tilesheet.txt");
            AddHeroPoseAnimation(hero, idleTileset, CharacterPose.Idle);
        }

        private void AddHeroJumpingPoseRenderer(ICharacter hero)
        {
            var jumpingTileset = CreateTileset(heroTextures.HeroJumping, "Content/jumping_tilesheet.txt");
            AddHeroPoseAnimation(hero, jumpingTileset, CharacterPose.Jumping);
        }

        private void AddHeroFallingPoseRenderer(ICharacter hero)
        {
            var fallingTileset = CreateTileset(heroTextures.HeroFalling, "Content/falling_tilesheet.txt");
            AddHeroPoseAnimation(hero, fallingTileset, CharacterPose.Falling);
        }

        private void AddHeroWalkingPoseRenderer(ICharacter hero)
        {
            var walkingTileset = CreateTileset(heroTextures.HeroWalking, "Content/walking_tilesheet.txt");
            AddHeroPoseAnimation(hero, walkingTileset, CharacterPose.Walking, new CharacterWalkingPoseAnimation(hero));
        }

        private Tileset CreateTileset(ITexture tilesetTexture, string tilesetTextureDescriptor)
        {
            var factory = new TilesetFactory(tilesetTexture);
            return factory.CreateFromDescriptor(tilesetTextureDescriptor);
        }

        private void AddHeroPoseAnimation(ICharacter hero, Tileset tileset, CharacterPose pose)
        {
            AddHeroPoseAnimation(hero, tileset, pose, new SimpleAnimation());
        }

        private void AddHeroPoseAnimation(ICharacter hero, Tileset tileset, CharacterPose pose, IAnimation animation)
        {
            tileset.ForEachTile((string tileId, ITexture tileTexture) => animation.AddFrame(CreateFrame(tileTexture)));

            hero.AddPoseAnimation(pose, animation);
        }

        private IAnimationFrame CreateFrame(ITexture tileTexture)
        {
            var textureRenderer = spriteRenderer.Create(tileTexture);
            return new TextureAnimationFrame(textureRenderer, 0.1f);
        }
    }
}
