using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic.CompilerServices;
using SDL2;
using testdrid.SdlWrapper;

namespace SkyscraperUI
{
    internal class CharSet
    {
        public CharSet(Texture texture)
        {
            _texture = texture;
            sourceRect.w = 24;
            sourceRect.h = 32;
            targetRect.w = 24;
            targetRect.h = 32;
            FacingDirection = CharSetFacing.Down;
            Stepping = CharSetStepping.Stand;
        }

        private Texture _texture;
        private byte _charNo;

        public byte CharacterNumber
        {
            get => _charNo;
            set
            {
                if (value > 7)
                    throw new ArgumentOutOfRangeException();
                _charNo = value;
            }
        }

        public bool IsMoving { get; set; }

        public CharSetFacing FacingDirection { get; set; }

        public CharSetStepping Stepping { get; set; }

        public int X { get; set; }

        public int Y { get; set; }

        private SDL.SDL_Rect sourceRect;
        private SDL.SDL_Rect targetRect;

        private static Point[] charNumberOffsets = new Point[]
        {
            new Point(0, 0),
            new Point(72, 0),
            new Point(144, 0),
            new Point(216, 0),
            new Point(0, 128),
            new Point(72, 128),
            new Point(144, 128),
            new Point(216, 128)
        };

        private static int[] facingOffsets = new int[] { 0, 32, 64, 96 };
        private static int[] steppingOffstes = new[] { 0,24, 48 };
        private static int steppingDelay = 10;
        private int steppingRemain;

        private Point home;

        #region AutoMove

        private bool autoMoveUsed;
        private int targetX;
        private int targetY;
        public void AutoMoveTo(Point p)
        {
            autoMoveUsed = true;
            targetX = p.X;
            targetY = p.Y;
            IsMoving = true;
        }

        public bool AutoMoveTargetReached => (targetX == X) && (targetY == Y);

        public bool AutoMoving 
        { 
            get => autoMoveUsed;
            set => autoMoveUsed = value;
        }
        #endregion

        #region Home

        public void SetHome(Point p)
        {
            home = p;
        }

        public void AutoMoveToHome()
        {
            AutoMoveTo(home);
        }

        public int GetHomeX()
        {
            return home.X;
        }

        public int GetHomeY()
        {
            return home.Y;
        }

        #endregion
        public void Render(Renderer renderer)
        {
            if (autoMoveUsed)
            {
                if (targetY > Y)
                {
                    FacingDirection = CharSetFacing.Down;
                    Y++;
                }
                else if (targetY < Y)
                {
                    FacingDirection = CharSetFacing.Up;
                    Y--;
                }
                else if (targetX > X)
                {
                    FacingDirection = CharSetFacing.Right;
                    X++;
                }
                else if (targetX < X)
                {
                    FacingDirection = CharSetFacing.Left;
                    X--;
                }
                else
                {
                    FacingDirection = CharSetFacing.Down;
                    Stepping = CharSetStepping.Stand;
                    IsMoving = false;
                }
            }
            sourceRect.x = 0;
            sourceRect.y = 0;

            sourceRect.x += charNumberOffsets[_charNo].X;
            sourceRect.y += charNumberOffsets[_charNo].Y;
            sourceRect.x += steppingOffstes[(byte)Stepping];
            sourceRect.y += facingOffsets[(byte)FacingDirection];

            if (IsMoving)
            {
                steppingRemain++;
                if (steppingRemain == steppingDelay)
                {
                    steppingRemain = 0;
                    switch (Stepping)
                    {
                        case CharSetStepping.Stand:
                            Stepping = CharSetStepping.RightFootForward;
                            break;
                        case CharSetStepping.RightFootForward:
                            Stepping = CharSetStepping.LeftFootForward;
                            break;
                        case CharSetStepping.LeftFootForward:
                            Stepping = CharSetStepping.Stand;
                            break;
                        default:
                            Stepping = CharSetStepping.Stand;
                            break;
                    }
                }
            }

            targetRect.x = X;
            targetRect.y = Y;
            renderer.Copy(_texture, ref sourceRect, ref targetRect);
        }
    }

    enum CharSetFacing : byte
    {
        Up = 0,
        Right = 1,
        Down = 2,
        Left = 3
    }

    enum CharSetStepping : byte
    {
        LeftFootForward = 0,
        Stand = 1,
        RightFootForward = 2
    }
}
