using Microsoft.Xna.Framework;
using MonoGame.FourEngine;
using MonoGame.FourEngine.Raycast;
using MonoGame.FourEngine.Resources;
using System;

namespace Raycast.Win32.Entities
{
    public class SegmentedSkyBox2D : Entity
    {
        public SegmentedSkyBox2D(IRaycastCamera camera, SpriteDefinition spriteDefinition)
        {
            Components.Add(new SkyBox2DComponent(camera, spriteDefinition));
        }

        public SegmentedSkyBox2D(IRaycastCamera camera, string fileName, Point size) 
            : this(
                camera, 
                new SpriteDefinition
                {
                    FileName = fileName,
                    Size = size
                })
        { }

        class SkyBox2DComponent : Component
        {
            public const int SegmentQuantity = 25;
            public const int CorrectionSize = 2;

            private readonly IRaycastCamera _camera;
            private readonly Sprite _sprite;

            private float _percent;

            public SkyBox2DComponent(IRaycastCamera camera, SpriteDefinition spriteDefinition)
            {
                _camera = camera;
                _sprite = new Sprite(spriteDefinition);
            }

            public override void OnUpdate(UpdateEventArgs args)
            {
                var angle = 
                _percent = (float)
                    ((Math.PI + Math.Atan2(_camera.Direction.Y, _camera.Direction.X))
                    / (Math.PI * 2));
            }

            public override void OnDraw(DrawEventArgs args)
            {
                var segmentSize = args.Scene.DrawingSurface.Width / SegmentQuantity;
                for (var i = 0; i < SegmentQuantity; i++)
                {
                    var start = segmentSize * i - (int)(_sprite.Size.X * _percent);
                    if (start < 0) start += _sprite.Size.X;
                    var end = start + segmentSize;

                    var verticalCorrection = Math.Abs(i - SegmentQuantity / 2 + 1) * CorrectionSize;

                    // Normal segment
                    if (end <= _sprite.Size.X)
                    {
                        args.Batch.Draw(
                            _sprite.Texture,
                            new Rectangle(segmentSize * i, -verticalCorrection, segmentSize, _sprite.Size.Y + verticalCorrection * 2),
                            new Rectangle(start, 0, segmentSize, _sprite.Size.Y),
                            Color.White);
                    }
                    // Splitted segment
                    else
                    {
                        var firstSegmentWidth = _sprite.Size.X - start;
                        var secondSegmentWidth = segmentSize - firstSegmentWidth;
                        args.Batch.Draw(
                            _sprite.Texture,
                            new Rectangle(segmentSize * i, -verticalCorrection, firstSegmentWidth, _sprite.Size.Y + verticalCorrection * 2),
                            new Rectangle(start, 0, firstSegmentWidth, _sprite.Size.Y),
                            Color.White);
                        args.Batch.Draw(
                            _sprite.Texture,
                            new Rectangle(segmentSize * i + firstSegmentWidth, -verticalCorrection, secondSegmentWidth, _sprite.Size.Y + verticalCorrection * 2),
                            new Rectangle(0, 0, secondSegmentWidth, _sprite.Size.Y),
                            Color.White);
                    }
                }
            }
        }
    }
}