using MemberCenter.Web.Models.Admin;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OpenIddict.Abstractions;

namespace MemberCenter.Web.Controllers.Admin;

[Authorize(Policy = "Admin")]
[Route("admin/oauth-clients")]
public class OAuthClientsController : Controller
{
    private readonly IOpenIddictApplicationManager _applicationManager;

    public OAuthClientsController(IOpenIddictApplicationManager applicationManager)
    {
        _applicationManager = applicationManager;
    }

    [HttpGet("")]
    public async Task<IActionResult> Index()
    {
        var results = new List<object>();
        await foreach (var application in _applicationManager.ListAsync())
        {
            results.Add(new
            {
                id = await _applicationManager.GetIdAsync(application),
                name = await _applicationManager.GetDisplayNameAsync(application),
                client_id = await _applicationManager.GetClientIdAsync(application),
                client_type = await _applicationManager.GetClientTypeAsync(application),
                redirect_uris = await _applicationManager.GetRedirectUrisAsync(application)
            });
        }

        return View(results);
    }

    [HttpGet("create")]
    public IActionResult Create()
    {
        return View(new OAuthClientFormViewModel());
    }

    [HttpPost("create")]
    public async Task<IActionResult> Create(OAuthClientFormViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        var descriptor = new OpenIddictApplicationDescriptor
        {
            ClientId = Guid.NewGuid().ToString("N"),
            DisplayName = model.Name,
            ClientType = model.ClientType,
            Permissions =
            {
                OpenIddictConstants.Permissions.Endpoints.Authorization,
                OpenIddictConstants.Permissions.Endpoints.Token,
                OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
                OpenIddictConstants.Permissions.GrantTypes.RefreshToken,
                OpenIddictConstants.Permissions.ResponseTypes.Code,
                OpenIddictConstants.Permissions.Scopes.Email,
                OpenIddictConstants.Permissions.Scopes.Profile,
                "scp:openid"
            }
        };

        foreach (var uri in model.RedirectUris.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
        {
            descriptor.RedirectUris.Add(new Uri(uri));
        }

        descriptor.Properties["tenant_id"] = System.Text.Json.JsonSerializer.SerializeToElement(model.TenantId.ToString());

        await _applicationManager.CreateAsync(descriptor);
        return RedirectToAction("Index");
    }

    [HttpGet("edit/{id}")]
    public async Task<IActionResult> Edit(string id)
    {
        var app = await _applicationManager.FindByIdAsync(id);
        if (app is null)
        {
            return NotFound();
        }

        var redirectUris = await _applicationManager.GetRedirectUrisAsync(app);
        var properties = await _applicationManager.GetPropertiesAsync(app);
        var tenantId = properties.TryGetValue("tenant_id", out var value) ? value.GetString() : string.Empty;

        return View(new OAuthClientFormViewModel
        {
            TenantId = Guid.TryParse(tenantId, out var parsed) ? parsed : Guid.Empty,
            Name = await _applicationManager.GetDisplayNameAsync(app) ?? string.Empty,
            ClientType = await _applicationManager.GetClientTypeAsync(app) ?? "public",
            RedirectUris = string.Join(",", redirectUris.Select(u => u.ToString()))
        });
    }

    [HttpPost("edit/{id}")]
    public async Task<IActionResult> Edit(string id, OAuthClientFormViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        var app = await _applicationManager.FindByIdAsync(id);
        if (app is null)
        {
            return NotFound();
        }

        var descriptor = new OpenIddictApplicationDescriptor();
        await _applicationManager.PopulateAsync(descriptor, app);

        descriptor.DisplayName = model.Name;
        descriptor.ClientType = model.ClientType;
        descriptor.RedirectUris.Clear();
        foreach (var uri in model.RedirectUris.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
        {
            descriptor.RedirectUris.Add(new Uri(uri));
        }
        descriptor.Properties["tenant_id"] = System.Text.Json.JsonSerializer.SerializeToElement(model.TenantId.ToString());

        await _applicationManager.UpdateAsync(app, descriptor);
        return RedirectToAction("Index");
    }

    [HttpPost("delete/{id}")]
    public async Task<IActionResult> Delete(string id)
    {
        var app = await _applicationManager.FindByIdAsync(id);
        if (app is null)
        {
            return NotFound();
        }

        await _applicationManager.DeleteAsync(app);
        return RedirectToAction("Index");
    }
}
