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

namespace Web.Pages
{
 public partial class Index
 {
  #region DI
  [Inject]
  public BlazorUtil Util { get; set; } = null;
  [Inject]
  public MiracleListAPI.MiracleListProxy Proxy { get; set; } = null;
  [Inject]
  public NavigationManager NavigationManager { get; set; }
  [Inject]
  AuthenticationStateProvider mLAuthenticationStateProvider { get; set; } = null;
  #endregion

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

  #region einfache Properties zur Datenbindung
  List<BO.Category> categorySet { get; set; }
  List<BO.Task> taskSet { get; set; }
  BO.Category category { get; set; }
  BO.Task task { get; set; }
  string newCategoryName { get; set; }
  string newTaskTitle { get; set; }
  string username { get; set; }
  string token = "";
  #endregion

  // ASP.NET Core SignalR-Verbindung
  private HubConnection _hubConnection;

  /// <summary>
  /// Lebenszyklusereignis: Komponente wird initialisiert
  /// </summary>
  /// <returns></returns>
  protected override async Task OnInitializedAsync()
  {
   Util.Log((nameof(Index) + "." + "OnInitializedAsync"));

   #region CheckUser
   var u = (await authenticationStateTask).User;
   if (!u.Identity.IsAuthenticated) { Util.Log(nameof(Index) + ": No User!"); NavigationManager.NavigateTo("Login"); return; }

   username = u.Identity.Name;
   Util.Log(nameof(Index) + ".Current User: " + username);
   try
   {
    token = u.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid).Value;
   }
   catch (Exception ex)
   {
    Util.Log("Fehler beim Zugriff auf Claim:" + ex.ToString());
   }
   #endregion

   // Lade Daten (Kategorieliste)
   await ShowCategorySet();
  }

  protected override async Task OnAfterRenderAsync(bool firstRender)
  {
   Console.WriteLine((nameof(TaskEdit) + "." + "OnAfterRenderAsync"));

   if (firstRender)
   {
    // Abfrage user, damit sichergestellt ist, dass auch Proxy.BaseUrl aktuell ist!!!
    var u = (await authenticationStateTask).User;

    #region ---- ASP.NET Core SignalR-Verbindung aufbauen
    var hubURL = new Uri(new Uri(Proxy.BaseUrl), "MLHub").ToString();
    Console.WriteLine("SignalR: Connect to " + hubURL);
    _hubConnection = new HubConnectionBuilder()
        .WithUrl(hubURL)
        .Build();

    // --- Reaktion auf eingehende Nachricht
    _hubConnection.On<string>("CategoryListUpdate", async (connectionID) =>
    {
     Util.Log($"SignalR.Received.CategoryListUpdate: {connectionID}");
     await ShowCategorySet();
     this.StateHasChanged();
    });
    // --- Reaktion auf eingehende Nachricht
    _hubConnection.On<string, int>("TaskListUpdate", async (connectionID, categoryID) =>
    {
     Util.Log($"SignalR.Received.TaskListUpdate: {connectionID}/{categoryID}");
     if (categoryID == this.category.CategoryID) await ShowTaskSet(this.category);
     StateHasChanged();
    });
    await _hubConnection.StartAsync();
    // Registrieren für Events
    await _hubConnection.SendAsync("Register", username);
    Util.Log("SignalR.Connection gestartet!");
    #endregion

   }
  }

  /// <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 async Task NewCategory_Keyup(KeyboardEventArgs e)
  {
   Util.Log("NewCategory_KeyPress: " + e.Key);
   if (e.Key == "Enter")
   {
    Util.Log("CreateCategory: " + this.newCategoryName);
    if (!String.IsNullOrEmpty(this.newCategoryName)) await 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 async Task NewTask_Keyup(KeyboardEventArgs e)
  {
   Util.Log("NewCategory_KeyPress: " + e.Key);
   if (e.Key == "Enter")
   {
    Util.Log("CreateTask: " + this.newTaskTitle);
    if (!String.IsNullOrEmpty(this.newTaskTitle)) await CreateTask(this.newTaskTitle);
    newTaskTitle = "";
   }
  }

  public async Task ReloadTasks(int taskID)
  {
   Util.Log(nameof(ReloadTasks) + ": Changed Task=" + taskID);

   await ShowTaskSet(this.category);
   this.task = null;
   Util.Log("Done: " + nameof(ReloadTasks) + ": Changed Task=" + taskID);
   SendTaskListUpdate();
  }

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

  public async Task ShowTaskSet(BO.Category c)
  {
   Util.Log(nameof(ShowTaskSet) + ": " + c.CategoryID + " (" + c.Name + ")");
   this.category = c;
   this.taskSet = await Proxy.TaskSetAsync(c.CategoryID, token);
   Util.Log(nameof(ShowTaskSet) + ": " + this.taskSet.Count + " Tasks in Category " + c.CategoryID + " (" + c.Name + ")");
  }

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

  public async System.Threading.Tasks.Task RemoveTask(BO.Task t)
  {
   if (!await Util.Confirm("Aufgabe #" + t.TaskID, "Endgültig löschen?")) return;
   await Proxy.DeleteTaskAsync(t.TaskID, token);
   await ShowTaskSet(this.category);
   this.task = null;
   SendTaskListUpdate();
  }

  /// <summary>
  /// Ereignisbehandlung: Benutzer löscht Kategorie
  /// </summary>
  /// <param name="c">zu löschende Kategorie</param>
  public async System.Threading.Tasks.Task 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 WebAPI-Aufruf
   await Proxy.DeleteCategoryAsync(c.CategoryID, token);
   // lokalen Zustand zurücksetzen
   this.category = null;
   // Liste der Kategorien neu laden
   await ShowCategorySet();
   // Benachrichtigung an alle Clients via ASP.NET Core SignalR
   SendCategoryListUpdate();
  }

  public async System.Threading.Tasks.Task CreateCategory(string newCategoryName)
  {
   if (string.IsNullOrEmpty(newCategoryName)) return;
   Util.Log("createCategory: " + newCategoryName);
   var newcategory = await Proxy.CreateCategoryAsync(newCategoryName, token);
   await ShowCategorySet();
   await ShowTaskSet(newcategory);

   SendCategoryListUpdate();
  }

  public async System.Threading.Tasks.Task ChangeTask(BO.Task t)
  {
   Util.Log("Change Task: " + t.TaskID + " Done: " + t.Done);
   await Proxy.ChangeTaskAsync(t, token);
   SendTaskListUpdate();
  }

  public async System.Threading.Tasks.Task CreateTask(string newTaskTitle)
  {
   if (string.IsNullOrEmpty(newTaskTitle)) return;
   Util.Log("createTask: " + newTaskTitle + " in category: " + this.category.Name);
   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;

   await Proxy.CreateTaskAsync(t, token);
   await ShowTaskSet(this.category);
   this.newTaskTitle = "";

   SendTaskListUpdate();
  }

  /// <summary>
  /// Lädt die Liste der Kategorien und zeigt die Aufgaben der ersten Kategorie
  /// </summary>
  /// <returns></returns>
  public async System.Threading.Tasks.Task ShowCategorySet()
  {
   categorySet = await Proxy.CategorySetAsync(token);
   Util.Log("Loaded Categories: " + categorySet.Count);
   if (this.category == null && this.categorySet.Count > 0) await ShowTaskSet(categorySet[0]);
  }

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

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

  }
 } // end class Index
}