using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using System.Text;
using System.Threading.Tasks;

namespace Echo.Core.Common.Packed
{
    [StructLayout(LayoutKind.Sequential)]
    public readonly partial struct Float4
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public Float4(in Vector128<float> v) => this.v = v;

        public readonly Vector128<float> v;

        public float X
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => v.GetElement(0);
        }

        public float Y
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => v.GetElement(1);
        }

        public float Z
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => v.GetElement(2);
        }

        public float W
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => v.GetElement(3);
        }


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        Float4 Shuffle(byte shuffle) => new(Sse.Shuffle(v, v, shuffle));

        [EditorBrowsableAttribute(EditorBrowsableState.Never), DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)] public Float4 XYXY => Shuffle((0 << 0) | (1 << 2) | (0 << 4) | (1 << 6));

        [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Float4 operator -(in Float4 first, in Float4 second) => new(Sse.Subtract(first.v, second.v));

        [MethodImpl(MethodImplOptions.AggressiveInlining)] public Float4 Max(in Float4 other) => new(Sse.Max(v, other.v));

        public static Float4 Zero => (Float4)0f;

        [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Float4(float value) => new(Vector128.Create(value));

        [MethodImpl(MethodImplOptions.AggressiveInlining)] public Float4 Min(in Float4 other) => new(Sse.Min(v, other.v));

        [EditorBrowsableAttribute(EditorBrowsableState.Never), DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)] public Float4 __ZW => Blend(0b0011);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        Float4 Blend(byte blend) => new(Sse41.Blend(v, Vector128<float>.Zero, blend)); //OPTIMIZE: we can use _mm_insert_ps here to save one instruction

        public Float4 Absoluted
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                Vector128<uint> mask = Vector128.Create(~0u >> 1);
                return new Float4(Sse.And(v, mask.AsSingle()));
            }
        }
    }
}
