#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
#pragma warning disable IDE1006 // Naming Styles

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Volpe.Cafe.Utils.Win32Native
{
    /// <summary>
    /// *** WARNING -- USE WITH CAUTION *** <br/>
    /// Use provided wrappers in <see cref="Win32"/> class whenever possible.<br/>
    /// <br/>
    /// Defines native data types and constants.
    /// </summary>
    public class NativeMethods
    {
        internal static T StructFromPtr<T>(IntPtr ptr)
        {
            return (T)Marshal.PtrToStructure(ptr, typeof(T));
        }

        internal static IntPtr StructToPtr<T>(T value)
        {
            IntPtr ptr = new IntPtr();
            Marshal.StructureToPtr(value, ptr, false);
            return ptr;
        }


        /// <summary>
        /// Defines the x- and y-coordinates of a point.
        /// </summary>
        /// <remarks>
        /// For more info see Microsoft docs:<br/>
        /// https://learn.microsoft.com/en-us/windows/win32/api/windef/ns-windef-point
        /// </remarks>
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public POINT(int x, int y)
            {
                this.x = x;
                this.y = y;
            }

            public POINT(Point pt) : this(pt.X, pt.Y) { }

            // x-/y-coordinates of the point
            public int x;
            public int y;

            public override string ToString()
            {
                return $"{{x={this.x}, y={this.y}}}";
            }

            public Point ToPoint()
            {
                return new Point(this.x, this.y);
            }

            public IntPtr ToPtr()
            {
                return StructToPtr(this);
            }

            public static POINT FromPtr(IntPtr lParam)
            {
                return StructFromPtr<POINT>(lParam);
            }

        }

        /// <summary>
        /// Defines the coordinates of the upper-left and lower-right corners of a rectangle.
        /// </summary>
        /// <remarks>
        /// For more info see Microsoft docs:<br/>
        /// https://learn.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect
        /// </remarks>
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public RECT(int left, int top, int right, int bottom)
            {
                this.left = left;
                this.top = top;
                this.right = right;
                this.bottom = bottom;
            }

            public RECT(Rectangle rect) : this(rect.Left, rect.Top, rect.Right, rect.Bottom) { }

            // x-/y-coordinates of the upper-left corner of the rectangle
            public int left, top;
            // x-/y-coordinates of the lower-right corner of the rectangle
            public int right, bottom;

            public Point Location => new Point(this.left, this.top);
            public Size Size => new Size(this.right - this.left, this.bottom - this.top);

            public override string ToString()
            {
                return $"{{left={this.left}, top={this.top}, right={this.right}, bottom={this.bottom}}}";
            }

            public Rectangle ToRectangle()
            {
                return new Rectangle(this.Location, this.Size);
            }

            public IntPtr ToPtr()
            {
                return StructToPtr(this);
            }

            public static RECT FromPtr(IntPtr lParam)
            {
                return StructFromPtr<RECT>(lParam);
            }

            public static RECT FromXYWH(int x, int y, int width, int height)
            {
                return new RECT(x, y, x + width, y + height);
            }

        }

        /// <summary>
        /// Contains information about the size and position of a window.
        /// </summary>
        /// <remarks>
        /// For more info see Microsoft docs:<br/>
        /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-windowpos
        /// </remarks>
        [StructLayout(LayoutKind.Sequential)]
        public struct WINDOWPOS
        {
            public IntPtr hwnd;
            public IntPtr hwndInsertAfter;
            public int x;
            public int y;
            public int cx;
            public int cy;
            public int flags;
        }

        /// <summary>
        /// Contains information that an application can use while processing the <see cref="WM.NCCALCSIZE"/> message
        /// to calculate the size, position, and valid contents of the client area of a window. 
        /// </summary>
        /// <remarks>
        /// For more info see Microsoft docs:<br/>
        /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-nccalcsize_params
        /// </remarks>
        [StructLayout(LayoutKind.Sequential)]
        public struct NCCALCSIZE_PARAMS
        {
            public NCCALCSIZE_PARAMS(RECT newWindow, RECT oldWindow, RECT clientWindow, IntPtr windowPos)
            {
                this.NewWindow = newWindow;
                this.OldWindow = oldWindow;
                this.ClientWindow = clientWindow;
                this.WindowPos = windowPos;
            }

            /// <summary>
            /// Contains the new coordinates of a window that has been moved or resized.
            /// </summary>
            public RECT NewWindow;

            /// <summary>
            /// Contains the coordinates of the window before it was moved or resized.
            /// </summary>
            public RECT OldWindow;

            /// <summary>
            /// Contains the coordinates of the window's client area before the window was moved or resized.
            /// </summary>
            public RECT ClientWindow;

            /// <summary>
            /// A pointer to a <see cref="WINDOWPOS"/> structure that contains the size and position values specified
            /// in the operation that moved or resized the window.
            /// </summary>
            public IntPtr WindowPos;

            /// <summary>
            /// Gets <see cref="WindowPos"/> as a <see cref="WINDOWPOS"/> structure.
            /// </summary>
            public WINDOWPOS WindowPosStruct => (WINDOWPOS)Marshal.PtrToStructure(this.WindowPos, typeof(WINDOWPOS));

            public IntPtr ToPtr()
            {
                return StructToPtr(this);
            }

            public static NCCALCSIZE_PARAMS FromPtr(IntPtr lParam)
            {
                return StructFromPtr<NCCALCSIZE_PARAMS>(lParam);
            }

        }

    }
}
