using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WK5_Blazor
{
    /// <summary>
    /// Stellt Daten für eine Sperrung einer Seite durch einen Mitarbeiter dar.
    /// </summary>
    public class ActivePage
    {
        /// <summary>
        /// Ruft ab, welche Seite derzeit gesperrt ist.
        /// </summary>
        public PageType Type { get; }
        /// <summary>
        /// Ruft den eindeutigen Identifier der Seite ab.
        /// </summary>
        public string PageId { get; }
        /// <summary>
        /// Ruft die PersonalNummer des Mitarbeiters ab, der die Seite gerade sperrt.
        /// </summary>
        public int UserId { get; }
        /// <summary>
        /// Ruft den Zeitpunkt des Beginns der Sperre durch den Mitarbeiter ab.
        /// </summary>
        public DateTime Timestamp { get; private set; }
        /// <summary>
        /// Erstellt einen neuen ActivePage Datensatz
        /// </summary>
        /// <param name="type">Der typ der Seite die geseprrt werden soll</param>
        /// <param name="pageId">Der Identifier der Seite. Z.B. die Auftragsnummer, oder die Bestellnummer</param>
        /// <param name="userId">Die Mitarbeiter ID</param>
        public ActivePage(PageType type, string pageId, int userId)
        {
            Type = type;
            PageId = pageId;
            UserId = userId;
            Timestamp = DateTime.Now;
        }
        /// <summary>
        /// Aktualisiert den <see cref="Timestamp"/> auf die aktuelle Zeit.
        /// </summary>
        public void UpdateTimestamp()
        {
            Timestamp = DateTime.Now;
        }
    }
    public static class ActivePages
    {
        /// <summary>
        /// Ruft alle derzeit gesperrten Seiten ab.
        /// </summary>
        public static List<ActivePage> Pages { get; } = new List<ActivePage>();
        /// <summary>
        /// Fügt eine <see cref="ActivePage"/> zur Liste der gesperrten Seiten hinzu.
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        public static (bool success, ActivePage page) AddActivePage(ActivePage page)
        {
            var suchePage = Pages.FirstOrDefault(x => x.Type == page.Type && x.PageId == page.PageId);

            if (suchePage is null)
            {
                Pages.Add(page);
                return (true, page);
            }

            // Wenn die UserId identisch ist, dann darf der User die Seite öffnen
            if (suchePage.UserId == page.UserId)
            {
                // Damit die Sperre nicht nach 10 Minuten ausläuft, erhöhen wir die Sperrzeit.
                suchePage.UpdateTimestamp();
                return (true, suchePage);
            }

            // Wenn der Browser gesschlossen wird, dann ist die Seite noch gesperrt, daher geben wir automatisch nach 10 Minuten alles wieder frei
            if(suchePage.Timestamp.AddMinutes(10) < DateTime.Now)
            {
                RemoveActivePage(suchePage);
                Pages.Add(page);
                return (true, page);
            }


            return (false, suchePage);
        }
        /// <summary>
        /// Entfernt eine <see cref="ActivePage"/> aus den gesperrten Seiten.
        /// </summary>
        /// <param name="page"></param>
        public static void RemoveActivePage(ActivePage? page)
        {
            if (page is not null)
            {
                Pages.Remove(page);
            }
        }
    }
    /// <summary>
    /// Stellt eine Schnittstelle zur Generalisierung der Implementierung für eine <see cref="ActivePage"/> zur Verfügung.
    /// </summary>
    public interface IActivePage : IAsyncDisposable
    {
        /// <summary>
        /// Ruft die <see cref="ActivePage"/> für die Sperre ab.
        /// <para>
        /// Diese enthält alle Daten über die derzeite Sperre der Seite.
        /// </para>
        /// </summary>
        public ActivePage? Page { get; set; }
        /// <summary>
        /// Ruft einen Wert ab, der angibt, ob die Seite bereits durch einen anderen Mitarbeiter gesperrt ist, oder legt diesen fest.
        /// </summary>
        public bool SperreDurchAnderenUser { get; set; }
        /// <summary>
        /// Prüft ob die Seite bereits durch einen anderen User gesperrt worden ist. Falls nicht, wird die Seite für den aktuellen User gesperrt.
        /// </summary>
        /// <returns></returns>
        public Task CheckActivePageAsync();
    }

    /// <summary>
    /// Eine Auflistung aller Seiten, die nur von einem Mitarbeiter gleichzeitig geöffnet sein können.
    /// </summary>
    public enum PageType
    {
        Artikel,
        Angebot,
        Auftrag,
        Lieferschein,
        Rechnung,
        Gutschrift,
        Zugang,
        Lagerregal,
        Kunde,
        Lieferant,
        Bestellung,
        RMA
    }
}
