#pragma warning disable 1998
using BL;
using BO;
using ITVisions.Blazor;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Claims;
using System.Threading.Tasks;

namespace Web.Pages
{
 public partial class Index
 {
  [Inject]
  public BlazorUtil Util { get; set; } = null;

  [Inject]
  public NavigationManager NavigationManager { get; set; } = null;

  [CascadingParameter] Task<AuthenticationState> authenticationStateTask { get; set; }

  int userID = 0;
  string status { get; set; } = "Loading...";
  List<Category> categorySet;
  List<BO.Task> taskSet;
  Category category;
  BO.Task task;
  string newCategoryName { get; set; }
  string newTaskTitle { get; set; }

  private HubConnection _hubConnection;

  #region Standard-Ereignisse
  protected async override System.Threading.Tasks.Task OnInitializedAsync()
  {

  }

  protected override async void OnAfterRender(bool firstRender)
  {
   if (firstRender)
   {
    #region SignalR konfigurieren und Nachricht empfangen
    var hubURL = NavigationManager.ToAbsoluteUri("/MLHub");
    Util.Log("SignalR.Connect to " + hubURL);
    _hubConnection = new HubConnectionBuilder()
        .WithUrl(hubURL)
        .Build();

    // --- eingehende Nachricht
    _hubConnection.On<string>("CategoryListUpdate", (connectionID) =>
    {
     Util.Log($"SignalR.CategoryListUpdate: {connectionID}");
     ShowCategorySet();
     StateHasChanged();
    });
    // --- eingehende Nachricht
    _hubConnection.On<string, int>("TaskListUpdate", (connectionID, categoryID) =>
    {
     Util.Log($"SignalR.TaskListUpdate: {connectionID}/{categoryID}");
     if (categoryID == this.category.CategoryID) ShowTaskSet(this.category);
     StateHasChanged();
    });
    // Verbindung zum SignalR-Hub starten
    await _hubConnection.StartAsync();

    // Registrieren für Events
    await _hubConnection.SendAsync("Register", userID.ToString());
    Util.Log("SignalR.Connection gestartet!");

    #endregion
   }
  }

  protected override async System.Threading.Tasks.Task OnAfterRenderAsync(bool firstRender)
  {
   this.status = "";
   if (firstRender)
   {
    Util.Log("Index.OnAfterRenderAsync");
    // Der Zugriff auf den Benutzer darf NICHT in OnInitializedAsync erfolgen, weil es da bei Blazor Server wegen des Pre-Rendering noch keinen Zugriff auf den Local Storage des Webbrowsers gibt!
    var u = (await authenticationStateTask).User;
    if (u == null) NavigationManager.NavigateTo("/login");
    userID = Convert.ToInt32(u.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid)?.Value ?? "0");
    if (userID == 0) NavigationManager.NavigateTo("/login");
    ShowCategorySet();
    this.StateHasChanged();
   }
  }
  #endregion

  #region Reaktionen auf eigene Ereignisse

  /// <summary>
  /// Use Keyup instead of Keypress as the actual data binding did not yet happen when Keypress is fired
  /// </summary>
  /// <param name="e"></param>
  /// <returns></returns>
  public void NewCategory_Keyup(KeyboardEventArgs e)
  {
   Util.Log("NewCategory_KeyPress: " + e.Key);
   if (e.Key == "Enter")
   {
    Util.Log("CreateCategory: " + this.newCategoryName);
    if (!String.IsNullOrEmpty(this.newCategoryName)) CreateCategory(this.newCategoryName);
    newCategoryName = "";
   }
  }

  /// <summary>
  /// Use Keyup instead of Keypress as the actual data binding did not yet happen when Keypress is fired
  /// </summary>
  /// <param name="e"></param>
  /// <returns></returns>
  public void NewTask_Keyup(KeyboardEventArgs e)
  {
   Util.Log("NewCategory_KeyPress: " + e.Key);
   if (e.Key == "Enter")
   {
    Util.Log("NewTask_Keyup: " + this.newTaskTitle);
    if (!String.IsNullOrEmpty(this.newTaskTitle)) CreateTask(this.newTaskTitle);
    newTaskTitle = "";
   }
  }
  public void ShowTaskSet(Category c)
  {
   Util.Log(nameof(ShowTaskSet) + ": " + c.CategoryID);
   this.category = c;
   this.taskSet = new TaskManager(userID).GetTaskSet(c.CategoryID);
  }

  public void ShowTaskDetail(BO.Task t)
  {
   Util.Log(nameof(ShowTaskDetail) + ": " + t.TaskID);
   this.task = t;
  }

  public async void RemoveTask(BO.Task t)
  {
   if (!await Util.Confirm("Aufgabe #" + t.TaskID, "Endgültig löschen?")) return;
   new TaskManager(userID).Remove(t.TaskID);
   ShowTaskSet(this.category);
   this.task = null;
   SendTaskListUpdate();
  }

  /// <summary>
  /// Ereignisbehandlung: Benutzer löscht Kategorie
  /// </summary>
  /// <param name="c">zu löschende Kategorie</param>
  public async void RemoveCategory(BO.Category c)
  {
   // Rückfrage (Browser-Dialog via JS!)
   if (!await Util.Confirm("Kategorie #" + c.CategoryID, "Mit allen Aufgaben endgültig löschen?")) return;
   // Löschen via BL-Aufruf
   new CategoryManager(userID).Remove(c.CategoryID);
   // lokalen Zustand zurücksetzen
   this.category = null;
   // Liste der Kategorien neu laden
   ShowCategorySet();
   // Benachrichtigung an alle Clients via ASP.NET Core SignalR
   SendCategoryListUpdate();
  }

  public void CreateCategory(string newCategoryName)
  {
   if (string.IsNullOrEmpty(newCategoryName)) return;
   Util.Log("createCategory: " + newCategoryName);
   var cat = new CategoryManager(userID).CreateCategory(newCategoryName);
   ShowCategorySet();
   ShowTaskSet(cat);
   SendCategoryListUpdate();
  }

  public void ChangeTask(BO.Task t)
  {
   Util.Log("Change Task: " + t.TaskID + " Done: " + t.Done);
   new TaskManager(userID).ChangeTask(t);
   SendTaskListUpdate();
  }

  public void CreateTask(string newTaskTitle)
  {
   if (string.IsNullOrEmpty(newTaskTitle)) return;
   var t = new BO.Task();
   t.TaskID = 0; // notwendig für Server, da der die ID vergibt
   t.Title = newTaskTitle;
   t.CategoryID = this.category.CategoryID;
   t.Importance = BO.Importance.B;
   t.Created = DateTime.Now;
   t.Due = null;
   t.Order = 0;
   t.Note = "";
   t.Done = false;

   if (string.IsNullOrEmpty(newTaskTitle)) return;
   Util.Log("CreateTask: " + newTaskTitle);
   new TaskManager(userID).CreateTask(t);
   ShowTaskSet(this.category);
   this.newTaskTitle = "";
   SendTaskListUpdate();
  }

  public void ShowCategorySet()
  {
   categorySet = new CategoryManager(userID).GetCategorySet();
   Util.Log("LoadCategories: " + categorySet.Count);
   if (this.category == null && this.categorySet.Count > 0) ShowTaskSet(categorySet[0]);
  }

  public void ReloadTasks(int taskID)
  {
   Util.Log(nameof(ReloadTasks) + ": Changed Task=" + taskID);
   ShowTaskSet(this.category);
   this.task = null;
   SendTaskListUpdate();
  }

  #endregion

  public bool IsConnected =>
    _hubConnection.State == HubConnectionState.Connected;

  /// <summary>
  /// Sende Nachricht an Hub via ASP.NET SignalR
  /// </summary>
  public async void SendCategoryListUpdate()
  {
   Util.Log("SignalR.SendCategoryListUpdate: " + userID.ToString());
   if (IsConnected) await _hubConnection.SendAsync("SendCategoryListUpdate", userID.ToString());
   else Util.Warn("SignalR.SendTaskListUpdate: not connected!", "");
  }

  /// <summary>
  /// Sende Nachricht an Hub via ASP.NET SignalR
  /// </summary>
  public async void SendTaskListUpdate()
  {
   Util.Log("SignalR.SendTaskListUpdate: " + userID.ToString() + "/" + this.category.CategoryID.ToString());
   if (IsConnected) await _hubConnection.SendAsync("SendTaskListUpdate", userID.ToString(), this.category.CategoryID);
   else Util.Warn("SignalR.SendTaskListUpdate: not connected!", "");
  }
 }
}