using IdentityModel.OidcClient;
using Serilog;
using Serilog.Sinks.SystemConsole.Themes;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;

namespace ConsoleClientWithBrowser
{
  public class Program
  {
    static string _authority = "https://api-login.ebp.com";
    static string _api = "https://api-developpeurs.ebp.com/gescom/api/v1/Folders";

    static OidcClient _oidcClient;
    static HttpClient _apiClient = new HttpClient { BaseAddress = new Uri(_api) };

    public static async Task Main()
    {
      Console.WriteLine("+-----------------------+");
      Console.WriteLine("|  Sign in with OIDC    |");
      Console.WriteLine("+-----------------------+");
      Console.WriteLine("");
      Console.WriteLine("Press any key to sign in...");
      Console.ReadKey();

      await SignIn();
    }

    private static async Task SignIn()
    {
      var browser = new SystemBrowser(3333);
      string redirectUri = "https://localhost:3333/api/login/SigninRedirect";


      var options = new OidcClientOptions
      {
        Authority = _authority,
        ClientId = "A_RENSEIGNER",
        ClientSecret = "A_RENSEIGNER",
        RedirectUri = redirectUri,
        Scope = "openid profile offline_access",
        FilterClaims = false,

        Browser = browser,
        IdentityTokenValidator = new JwtHandlerIdentityTokenValidator(),
        RefreshTokenInnerHttpHandler = new SocketsHttpHandler()
      };

      var serilog = new LoggerConfiguration()
          .MinimumLevel.Debug()
          .Enrich.FromLogContext()
          .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Code)
          .CreateLogger();

      options.LoggerFactory.AddSerilog(serilog);

      _oidcClient = new OidcClient(options);
      var result = await _oidcClient.LoginAsync(new LoginRequest());

      _apiClient = new HttpClient(result.RefreshTokenHandler)
      {
        BaseAddress = new Uri(_api)
      };

      ShowResult(result);
      await NextSteps(result);
    }

    private static void ShowResult(LoginResult result)
    {
      if (result.IsError)
      {
        Console.WriteLine("\n\nError:\n{0}", result.Error);
        return;
      }

      Console.WriteLine("\n\nClaims:");
      foreach (var claim in result.User.Claims)
      {
        Console.WriteLine("{0}: {1}", claim.Type, claim.Value);
      }

      var values = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(result.TokenResponse.Raw);

      Console.WriteLine($"token response...");
      foreach (var item in values)
      {
        Console.WriteLine($"{item.Key}: {item.Value}");
      }
    }

    private static async Task NextSteps(LoginResult result)
    {
      var currentAccessToken = result.AccessToken;
      var currentRefreshToken = result.RefreshToken;

      var menu = "  x...exit  c...call api   ";
      if (currentRefreshToken != null) menu += "r...refresh token   ";

      while (true)
      {
        Console.WriteLine("\n\n");

        Console.Write(menu);
        var key = Console.ReadKey();

        if (key.Key == ConsoleKey.X) return;
        if (key.Key == ConsoleKey.C) await CallApi();
        if (key.Key == ConsoleKey.R)
        {
          var refreshResult = await _oidcClient.RefreshTokenAsync(currentRefreshToken);
          if (refreshResult.IsError)
          {
            Console.WriteLine($"Error: {refreshResult.Error}");
          }
          else
          {
            currentRefreshToken = refreshResult.RefreshToken;
            currentAccessToken = refreshResult.AccessToken;

            Console.WriteLine("\n\n");
            Console.WriteLine($"access token:   {currentAccessToken}");
            Console.WriteLine($"refresh token:  {currentRefreshToken ?? "none"}");
          }
        }
      }
    }
    private static async Task CallApi()
    {
      _apiClient.DefaultRequestHeaders.Add("ebp-subscription-key", "ID_ABONNEMENT");


      var response = await _apiClient.GetAsync("");

      if (response.IsSuccessStatusCode)
      {
        var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
        Console.WriteLine("\n\n");
        Console.WriteLine(json.RootElement);
      }
      else
      {
        Console.WriteLine($"Error: {response.ReasonPhrase}");
      }
    }
  }
}