using Microsoft.AspNetCore.Components;
using MudBlazor;
using MarketData.Service;
using Microsoft.AspNetCore.Components.Authorization;
using eNavigator.Routes;
using MarketData.Utils;
using MarketData.MarketDataModel;
using eNavigator.Models;
using System.Text;

namespace eNavigator.Pages
{
  public partial class BollingerBands
  {
    [Inject]
    private AuthenticationStateProvider authenticationStateProvider { get; set; } = default;     

    [Inject]
    private NavigationManager NavigationManager { get; set; } = default!;    

    protected bool IsBusy { get; set; } = false;
    protected String BusyMessage { get; set;} = "";   

    protected List<SelectableSymbol> AvailableSymbols { get; set;} = new List<SelectableSymbol>{new SelectableSymbol(){Index=0,Name="---"}};
    protected SelectableSymbol SelectedSymbol { get; set; } = new SelectableSymbol(){Index=0,Name="---"};

    protected List<BollingerBandElement> BollingerBandElements { get; set; } = new List<BollingerBandElement>();

    protected List<int> AvailableDayCounts { get; set; } = new List<int>{60,90,120,180,360,720,1440};
    protected int SelectedDayCount { get; set; } = 120;

    protected String Heading { get; set; } = "";    

    protected List<ChartSeries> ChartSeriesCollection { get; set; } = new List<ChartSeries>();
    protected ChartOptions ChartingOptions{ get; set; } = new ChartOptions();

    protected String[] XAxisLabels { get; set; } = new String[]{""};

    protected override async Task OnInitializedAsync()
    {
      await base.OnInitializedAsync();
      AuthenticationState authenticationState = await authenticationStateProvider.GetAuthenticationStateAsync();
      if(!authenticationState.User.Identity.IsAuthenticated)
      {
          NavigationManager.NavigateTo(PageRoute.Login);
          return;
      }  
      await LoadSymbols();
      SelectedSymbol = AvailableSymbols.Count()>0 ? AvailableSymbols[0] : SelectedSymbol;  
      await LoadBollingerBands(SelectedSymbol.Name, SelectedDayCount);
      StateHasChanged();
      Task.Run(async () => await Task.Yield()).GetAwaiter();             
    } 

    private async Task LoadSymbols()
    {
      BusyMessage = $"Loading symbols...";
      IsBusy = true;
      ServiceResult serviceResult = await marketDataServiceClient.GetWatchList("Valuations"); 
      if(!serviceResult.Success)
      {
        DisplayToast("Error contacting server, could not load latest headlines.");
        return;
      }
      List<String> availableSymbolsList = (serviceResult.ContextSpecificResult as List<String>);
      List<SelectableSymbol> availableSymbols = new List<SelectableSymbol>();
      for(int index=0;index<availableSymbolsList.Count;index++)
      {
        availableSymbols.Add(new SelectableSymbol(){Name=availableSymbolsList[index],Index=index});
      }
      AvailableSymbols = availableSymbols; //(serviceResult.ContextSpecificResult as List<String>);
      DisplayToast($"Loaded {AvailableSymbols.Count} symbols in {Utility.FormatNumber(serviceResult.ElapsedTimeMS,0,true)}(ms).");
      IsBusy = false;
    }

    private async Task LoadBollingerBands(String symbol,int dayCount)
    {
      String companyName = "";
      BusyMessage = $"Loading {dayCount} day bollinger bands for {symbol} ...";
      IsBusy = true;

      ServiceResult serviceResult = await marketDataServiceClient.GetCompanyNameForSymbol(symbol);
      if(serviceResult.Success)
      {
        companyName = (serviceResult.ContextSpecificResult as String);
      }

      serviceResult = await marketDataServiceClient.GetBollingerBands(symbol,dayCount); 
      if(!serviceResult.Success)
      {
        DisplayToast("Error contacting server, could not load bollinger bands.");
        return;
      }
      BollingerBandElements = (serviceResult.ContextSpecificResult as List<BollingerBandElement>);
      // if(BollingerBandElements.Count()>0)
      // {
      //   Heading = SelectedSymbol + " - " + companyName + "("+ BollingerBandElements[BollingerBandElements.Count()-1].Date.ToShortDateString() + " Thru " + BollingerBandElements[0].Date.ToShortDateString()+ ")";
      // }
      DisplayToast($"Loaded {Utility.FormatNumber(BollingerBandElements.Count*13,0,true)} data points in {Utility.FormatNumber(serviceResult.ElapsedTimeMS,0,true)}(ms).");
      CreateHeading(companyName);
      CreateChartSeries();
      CreateChartOptions();
      CreateXAxisLabels();

      IsBusy = false;
    }

    private void DisplayToast(String message)
    {
      snackbarService.Add(new MarkupString($"<ul><li>{message}</li></ul>"));
    }        

    private async Task OnSymbolChanged()
    {
      await LoadBollingerBands(SelectedSymbol.Name, SelectedDayCount);
    }  

    private async Task OnDayCountChanged()
    {
      await LoadBollingerBands(SelectedSymbol.Name, SelectedDayCount);
    }  

    protected async Task RefreshClicked()
    {
      await Task.FromResult(true);
      await LoadBollingerBands(SelectedSymbol.Name,SelectedDayCount);
      StateHasChanged();
      Task.Run(async () => await Task.Yield()).GetAwaiter();     
    }    

    private void CreateHeading(String companyName)
    {
      if(0==BollingerBandElements.Count())
      {
        Heading = "";
        return;
      }
      BollingerBandElement bollingerBandElementCurrent = BollingerBandElements[0];
      BollingerBandElement bollingerBandElementPrev = BollingerBandElements[1];

      StringBuilder sb = new StringBuilder();
      sb.Append(companyName);
      sb.Append(" (");
      sb.Append(SelectedSymbol );
      sb.Append(") ");
      sb.Append(BollingerBandElements[BollingerBandElements.Count()-1].Date.ToShortDateString());
      sb.Append(" Thru ");
      sb.Append(BollingerBandElements[0].Date.ToShortDateString());

      if(BollingerBandElements.Count()<2)
      {
        Heading = sb.ToString();
        return;
      }
 
      double change=double.NaN;
      if(0.00!=bollingerBandElementCurrent.Close)
      {
        change = (bollingerBandElementCurrent.Close - bollingerBandElementPrev.Close) / bollingerBandElementCurrent.Close;
      }

      sb.Append(" ");
      sb.Append("(");
      sb.Append(Utility.FormatCurrency(bollingerBandElementCurrent.Close));
      sb.Append("/");
      sb.Append(Utility.FormatCurrency(bollingerBandElementCurrent.Low));
      if(!double.IsNaN(change))
      {
        sb.Append(",");
        sb.Append(change>=0.00?"+":"").Append(Utility.FormatPercent((double)change,2));
      }            
      sb.Append(")");      

      Heading = sb.ToString();
    }

    private void CreateXAxisLabels()
    {
      if(0==BollingerBandElements.Count())
      {
        return;
      }
      XAxisLabels = BuildXAxisLabels(6).ToArray();
    }

    private List<String> BuildXAxisLabels(int labels)
    {
      List<String> axisLabels = new List<String>();
      if(0==BollingerBandElements.Count())
      {
        return axisLabels;
      }    
      long dataPoints = BollingerBandElements.Count();
      int intervals = (int)( (double)dataPoints/(double)labels);
      for(int index=BollingerBandElements.Count()-1;index>=0;index--)
      {
        if(0==(index%intervals))
        {
          StringBuilder sb = new StringBuilder();
          DateTime date = BollingerBandElements[index].Date;
          sb.Append(date.Month.ToString());
          sb.Append("/");
          sb.Append(date.Year.ToString());
          axisLabels.Add(sb.ToString());
        }
        else
        {
          axisLabels.Add("");
        }
      }
      return axisLabels;
    }

    private void CreateChartOptions()
    {
      ChartingOptions = new ChartOptions()
      {
        LineStrokeWidth = 1,
        XAxisLines = true,
        YAxisFormat="c2",
        ChartPalette = new[]
        {
          "#0000FF",  // High
          "#FF0000",  // Low
          "#000000",  // Close
          "#800080",  // SMAN
          "#13A10E",  // K
          "#13A10E",  // L
          "#13A10E",  // KL1
          "#13A10E"   // LP1
        }
      };
    }

    private void CreateChartSeries()
    {
      ChartSeriesCollection = new List<ChartSeries>();

      if(0==BollingerBandElements.Count())
      {
        return;
      }

      double[] highData = new double[BollingerBandElements.Count()];
      double[] lowData =  new double[BollingerBandElements.Count()];
      double[] closeData =  new double[BollingerBandElements.Count()];
      double[] smanData =  new double[BollingerBandElements.Count()];
      double[] kData =  new double[BollingerBandElements.Count()];
      double[] lData =  new double[BollingerBandElements.Count()];
      double[] kl1Data =  new double[BollingerBandElements.Count()];
      double[] lp1Data =  new double[BollingerBandElements.Count()];

      for(int index=0;index<BollingerBandElements.Count();index++)
      {
        BollingerBandElement bollingerBandElement = BollingerBandElements[(BollingerBandElements.Count()-index)-1];
        highData[index] = bollingerBandElement.High;
        lowData[index] = bollingerBandElement.Low;
        closeData[index] = bollingerBandElement.Close;
        smanData[index] = bollingerBandElement.SMAN;
        kData[index] = bollingerBandElement.K;
        lData[index] = bollingerBandElement.L;
        kl1Data[index] = bollingerBandElement.KL1;
        lp1Data[index] = bollingerBandElement.LP1;
      }

      ChartSeries highSeries = new ChartSeries(){Name="High", Data=highData};
      ChartSeries lowSeries = new ChartSeries(){Name="Low", Data=lowData};
      ChartSeries closeSeries = new ChartSeries(){Name="Close", Data=closeData};
      ChartSeries smanSeries = new ChartSeries(){Name="SMAN", Data=smanData};
      ChartSeries kSeries = new ChartSeries(){Name="K", Data=kData};
      ChartSeries lSeries = new ChartSeries(){Name="L", Data=lData};
      ChartSeries kl1Series = new ChartSeries(){Name="KL1", Data=kl1Data};
      ChartSeries lp1Series = new ChartSeries(){Name="LP1", Data=lp1Data};

      ChartSeriesCollection.Add(highSeries);
      ChartSeriesCollection.Add(lowSeries);
      ChartSeriesCollection.Add(closeSeries);
      ChartSeriesCollection.Add(smanSeries);
      ChartSeriesCollection.Add(kSeries);
      ChartSeriesCollection.Add(lSeries);
      ChartSeriesCollection.Add(kl1Series);
      ChartSeriesCollection.Add(lp1Series);
    }
  }
}