// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS)
// Copyright (C) 2025-present LeonOS 2 Developer Team
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

using Cosmos.System;
using Cosmos.System.Graphics;
using CMLeonOS.Gui.SmoothMono;
using System;
using System.Collections.Generic;
using System.Drawing;

namespace CMLeonOS.Gui.UILib
{
    internal class Table : Control
    {
        public Table(Window parent, int x, int y, int width, int height) : base(parent, x, y, width, height)
        {
            OnDown = TableDown;
        }

        [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.ScrollbarUp.bmp")]
        private static byte[] scrollbarUpBytes;
        private static Bitmap scrollbarUpBitmap = new Bitmap(scrollbarUpBytes);

        [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.ScrollbarDown.bmp")]
        private static byte[] scrollbarDownBytes;
        private static Bitmap scrollbarDownBitmap = new Bitmap(scrollbarDownBytes);

        internal List<TableCell> Cells { get; set; } = new List<TableCell>();

        internal Action<int> TableCellSelected { get; set; }

        internal bool AllowDeselection { get; set; } = true;

        internal bool AllowSelection { get; set; } = true;

        private double scrollY = 0;

        private bool dragging = false;
        private int lastDragY = 0;

        private int _selectedCellIndex = -1;
        internal int SelectedCellIndex
        {
            get
            {
                return _selectedCellIndex;
            }
            set
            {
                if (_selectedCellIndex != value)
                {
                    _selectedCellIndex = value;
                    Render();
                }
            }
        }

        private int _scrollbarThickness = 20;
        internal int ScrollbarThickness
        {
            get
            {
                return _scrollbarThickness;
            }
            set
            {
                _scrollbarThickness = value;
                Render();
            }
        }

        private Color _background = UITheme.Surface;
        internal Color Background
        {
            get
            {
                return _background;
            }
            set
            {
                _background = value;
                Render();
            }
        }

        private Color _foreground = UITheme.TextPrimary;
        internal Color Foreground
        {
            get
            {
                return _foreground;
            }
            set
            {
                _foreground = value;
                Render();
            }
        }

        private Color _border = UITheme.SurfaceBorder;
        internal Color Border
        {
            get
            {
                return _border;
            }
            set
            {
                _border = value;
                Render();
            }
        }

        private Color _selectedBackground = UITheme.AccentLight;
        internal Color SelectedBackground
        {
            get
            {
                return _selectedBackground;
            }
            set
            {
                _selectedBackground = value;
                Render();
            }
        }

        private Color _selectedForeground = UITheme.TextPrimary;
        internal Color SelectedForeground
        {
            get
            {
                return _selectedForeground;
            }
            set
            {
                _selectedForeground = value;
                Render();
            }
        }

        private Color _selectedBorder = UITheme.Accent;
        internal Color SelectedBorder
        {
            get
            {
                return _selectedBorder;
            }
            set
            {
                _selectedBorder = value;
                Render();
            }
        }

        private int _cellHeight = 20;
        internal int CellHeight
        {
            get
            {
                return _cellHeight;
            }
            set
            {
                _cellHeight = value;
                Render();
            }
        }

        private Alignment _textAlignment = Alignment.Start;
        internal Alignment TextAlignment
        {
            get
            {
                return _textAlignment;
            }
            set
            {
                _textAlignment = value;
                Render();
            }
        }

        private void TableDown(int x, int y)
        {
            if ((CanScrollUp || CanScrollDown) && x >= (Width - _scrollbarThickness))
            {
                int allCellsHeight = Cells.Count * CellHeight;
                if (y < _scrollbarThickness && CanScrollUp)
                {
                    scrollY = Math.Max(0, scrollY - CellHeight);
                    Render();
                }
                if (y >= Height - _scrollbarThickness && CanScrollDown)
                {
                    scrollY = Math.Min(allCellsHeight - Height, scrollY + CellHeight);
                    Render();
                }
                if (y < Height - _scrollbarThickness && y >= _scrollbarThickness)
                {
                    dragging = true;
                    lastDragY = (int)MouseManager.Y;
                    Render();
                }
                return;
            }


            int scrollAdjustedY = (int)(y + scrollY);
            if (scrollAdjustedY < 0 || scrollAdjustedY > _cellHeight * Cells.Count)
            {
                if (AllowDeselection)
                {
                    SelectedCellIndex = -1;
                }
                return;
            }

            if (AllowSelection)
            {
                SelectedCellIndex = scrollAdjustedY / _cellHeight;
                TableCellSelected?.Invoke(_selectedCellIndex);
            }
        }

        private bool CanScrollUp
        {
            get
            {
                return scrollY > 0;
            }
        }

        private bool CanScrollDown
        {
            get
            {
                int allCellsHeight = Cells.Count * CellHeight;
                return (scrollY < 0) || ((allCellsHeight > Height) && (scrollY < (allCellsHeight - Height)));
            }
        }

        private void RenderScrollbar()
        {
            if (CanScrollUp || CanScrollDown)
            {
                /* Background */
                DrawFilledRectangle(Width - _scrollbarThickness, 0, _scrollbarThickness, Height, UITheme.SurfaceMuted);

                /* Track */
                int trackAvailableHeight = Height - (ScrollbarThickness * 2);
                double trackSize = (double)Height / (double)(Cells.Count * CellHeight);
                double trackProgress = (double)scrollY / (double)((Cells.Count * CellHeight) - Height);
                int trackY = (int)(_scrollbarThickness + (((double)trackAvailableHeight - ((double)trackAvailableHeight * trackSize)) * trackProgress));
                // Border
                DrawFilledRectangle(Width - _scrollbarThickness, 0, _scrollbarThickness, Height, UITheme.SurfaceBorder);
                // Background
                DrawFilledRectangle(Width - _scrollbarThickness + 1, trackY + 1, _scrollbarThickness - 2, (int)(trackSize * trackAvailableHeight) - 2, UITheme.AccentLight);

                /* Up arrow */
                // Border
                DrawFilledRectangle(Width - _scrollbarThickness, 0, _scrollbarThickness, _scrollbarThickness, UITheme.SurfaceBorder);
                // Background
                DrawFilledRectangle(Width - _scrollbarThickness + 1, 1, _scrollbarThickness - 2, _scrollbarThickness - 2, CanScrollUp ? UITheme.Surface : UITheme.SurfaceMuted);
                DrawImageAlpha(scrollbarUpBitmap, (int)((Width - _scrollbarThickness) + ((_scrollbarThickness / 2) - (scrollbarUpBitmap.Width / 2))), (int)((_scrollbarThickness / 2) - (scrollbarUpBitmap.Height / 2)));

                /* Down arrow */
                // Border
                DrawFilledRectangle(Width - _scrollbarThickness, Height - _scrollbarThickness, _scrollbarThickness, _scrollbarThickness, UITheme.SurfaceBorder);
                // Background
                DrawFilledRectangle(Width - _scrollbarThickness + 1, Height - _scrollbarThickness + 1, _scrollbarThickness - 2, _scrollbarThickness - 2, CanScrollDown ? UITheme.Surface : UITheme.SurfaceMuted);
                DrawImageAlpha(scrollbarDownBitmap, (int)((Width - _scrollbarThickness) + ((_scrollbarThickness / 2) - (scrollbarUpBitmap.Width / 2))), (int)((Height - _scrollbarThickness) + ((_scrollbarThickness / 2) - (scrollbarUpBitmap.Height / 2))));
            }
        }

        internal void ScrollToTop()
        {
            scrollY = 0;
            Render();
        }

        internal void ScrollToBottom()
        {
            int allCellsHeight = Cells.Count * CellHeight;
            if (allCellsHeight > Height)
            {
                scrollY = allCellsHeight - Height;
            }
            else
            {
                scrollY = 0;
            }
            Render();
        }

        internal override void Render()
        {
            int scrollMax = (Cells.Count * CellHeight) - Height;
            if (dragging)
            {
                scrollY += (int)(MouseManager.Y - lastDragY);
                lastDragY = (int)MouseManager.Y;
                if (MouseManager.MouseState != MouseState.Left)
                {
                    dragging = false;
                }
                WM.UpdateQueue.Enqueue(this);
            }
            else if (scrollY < 0 || scrollY > scrollMax)
            {
                double oldScrollY = scrollY;
                double move;
                if (scrollY > 0)
                {
                    move = (scrollMax - scrollY) / 8d;
                }
                else
                {
                    move = (-scrollY) / 8d;
                }
                scrollY += move;
                if (Math.Abs(scrollY - oldScrollY) > 0.05)
                {
                    WM.UpdateQueue.Enqueue(this);
                }
            }

            Clear(Background);

            for (int i = 0; i < Cells.Count; i++)
            {
                TableCell cell = Cells[i];
                bool selected = _selectedCellIndex == i;
                int contentWidth = Width - ((CanScrollUp || CanScrollDown) ? _scrollbarThickness : 0);
                Rectangle cellRect = new Rectangle(0, (int)((i * _cellHeight) - scrollY), contentWidth, _cellHeight);

                if (cellRect.Y < -cellRect.Height || cellRect.Y > Height)
                {
                    continue;
                }

                if (cell.BackgroundColourOverride != null)
                {
                    DrawFilledRectangle(cellRect.X, cellRect.Y, cellRect.Width, cellRect.Height, (Color)cell.BackgroundColourOverride);
                }
                else
                {
                    // Border.
                    DrawFilledRectangle(cellRect.X, cellRect.Y, cellRect.Width, cellRect.Height, selected ? _selectedBorder : _border);

                    // Background.
                    DrawFilledRectangle(cellRect.X + 1, cellRect.Y + 1, cellRect.Width - 2, cellRect.Height - 2, selected ? _selectedBackground : _background);
                }

                int textX;
                switch (_textAlignment)
                {
                    case Alignment.Start:
                        textX = cellRect.X + 6 + (cell.Image != null ? (CellHeight - FontData.Height) / 2 : 0);
                        break;
                    case Alignment.Middle:
                        textX = cellRect.X + (cellRect.Width / 2) - (cell.Text.Length * FontData.Width / 2);
                        break;
                    case Alignment.End:
                        textX = cellRect.X + cellRect.Width - (cell.Text.Length * FontData.Width);
                        break;
                    default:
                        throw new Exception("Invalid Table alignment!");
                }


                int textY = cellRect.Y + (cellRect.Height / 2) - (16 / 2);

                if (cell.Image != null)
                {
                    textX += (int)cell.Image.Width + 6;
                    DrawImageAlpha(cell.Image, cellRect.X + 4, (int)(cellRect.Y + (cellRect.Height / 2) - (cell.Image.Height / 2)));
                }

                if (cell.ForegroundColourOverride != null)
                {
                    DrawString(cell.Text, (Color)cell.ForegroundColourOverride, textX, textY);
                }
                else
                {
                    DrawString(cell.Text, selected ? SelectedForeground : Foreground, textX, textY);
                }

                DrawHorizontalLine(cellRect.Width - 2, 1, cellRect.Y + cellRect.Height - 1, UITheme.SurfaceBorder);
            }

            //DrawString($"{scrollY.ToString()} {dragging.ToString()} {scrollMax.ToString()}", Color.Red, 0, 0);

            RenderScrollbar();

            WM.Update(this);
        }
    }
}
