// 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 System;
using System.Drawing;

namespace CMLeonOS.Gui.UILib
{
    internal class Calendar : Control
    {
        public Calendar(Window parent, int x, int y, int width, int height) : base(parent, x, y, width, height)
        {
        }

        internal void SetCalendar(int year, int month)
        {
            _year = year;
            _month = month;
            Render();
        }

        private int _year = DateTime.Now.Year;
        internal int Year
        {
            get
            {
                return _year;
            }
            set
            {
                _year = value;
                Render();
            }
        }

        private int _month = DateTime.Now.Month;
        internal int Month
        {
            get
            {
                return _month;
            }
            set
            {
                _month = value;
                Render();
            }
        }

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

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

        private Color _weekendForeground = Color.Red;
        internal Color WeekendForeground
        {
            get
            {
                return _weekendForeground;
            }
            set
            {
                _weekendForeground = value;
                Render();
            }
        }

        private Color _todayBackground = Color.LightGray;
        internal Color TodayBackground
        {
            get
            {
                return _todayBackground;
            }
            set
            {
                _todayBackground = value;
                Render();
            }
        }

        private readonly string[] weekdaysShort = new string[]
        {
            "Mon",
            "Tue",
            "Wed",
            "Thu",
            "Fri",
            "Sat",
            "Sun"
        };

        private readonly string[] monthsLong = new string[]
        {
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December"
        };

        private int GetWeekdayIndex(DayOfWeek dayOfWeek)
        {
            return dayOfWeek switch
            {
                DayOfWeek.Monday => 0,
                DayOfWeek.Tuesday => 1,
                DayOfWeek.Wednesday => 2,
                DayOfWeek.Thursday => 3,
                DayOfWeek.Friday => 4,
                DayOfWeek.Saturday => 5,
                DayOfWeek.Sunday => 6,
                _ => throw new Exception("Invalid DayOfWeek.")
            };
        }

        private const int cellPadding = 4;

        internal override void Render()
        {
            Clear(_background);

            DateTime now = DateTime.Now;
            int daysInMonth = DateTime.DaysInMonth(_year, _month);
            int startingWeekday = GetWeekdayIndex(new DateTime(_year, _month, 1).DayOfWeek);

            int headerHeight = 68;

            Rectangle availableSpace = new Rectangle(0, headerHeight, Width, Height - headerHeight);

            int cellWidth = availableSpace.Width / 7;
            int cellHeight = availableSpace.Height / 5;

            /* Header */
            string title = $"{monthsLong[_month - 1]} {_year}";
            DrawString(title, _foreground, (Width / 2) - ((title.Length * 8) / 2), 12);
            for (int i = 0; i < 7; i++)
            {
                string weekday = weekdaysShort[i];
                DrawString(weekday, _foreground, (i * cellWidth) + ((cellWidth / 2) - weekday.Length * (8 / 2) / 2), 40);
            }

            /* Days */
            int cellX = startingWeekday;
            int cellY = 0;
            for (int i = 1; i <= daysInMonth; i++)
            {
                if (cellX > 6)
                {
                    cellX = 0;
                    cellY++;
                }

                string str = i.ToString();
                bool weekend = cellX >= 5;

                int cellWindowX = availableSpace.X + (cellX * cellWidth);
                int cellWindowY = availableSpace.Y + (cellY * cellHeight);

                int textWindowX = (cellWindowX + cellWidth) - (8 * str.Length) - cellPadding;
                int textWindowY = cellWindowY + cellPadding;

                if (_year == now.Year && _month == now.Month && i == now.Day)
                {
                    DrawFilledRectangle(cellWindowX, cellWindowY, cellWidth, cellHeight, _todayBackground);
                }

                DrawString(str, weekend ? _weekendForeground : _foreground, textWindowX, textWindowY);

                cellX++;
            }

            WM.Update(this);
        }
    }
}
