using FlatRender.IdentitySvc.Application.Services.Interfaces;
using FlatRender.IdentitySvc.Models.Requests;
using FlatRender.IdentitySvc.Models.Responses;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace FlatRender.IdentitySvc.Controllers;

[ApiController]
[Route("v1")]
[Authorize]
public class PlansController(IPlanService planService) : ControllerBase
{
    [AllowAnonymous]
    [HttpGet("plans")]
    [ProducesResponseType(typeof(object), 200)]
    public async Task<IActionResult> List([FromQuery] string? scope)
    {
        var plans = await planService.ListAsync(GetTenantIdOrNull(), scope);
        return Ok(new { data = plans });
    }

    [AllowAnonymous]
    [HttpGet("plans/{planId:guid}")]
    [ProducesResponseType(typeof(PlanResponse), 200)]
    public async Task<IActionResult> GetById(Guid planId)
        => Ok(await planService.GetByIdAsync(planId));

    [HttpGet("users/me/plan")]
    [ProducesResponseType(typeof(UserPlanResponse), 200)]
    public async Task<IActionResult> GetCurrentPlan()
        => Ok(await planService.GetCurrentPlanAsync(GetUserId()));

    [HttpPost("users/me/plan/purchase")]
    [ProducesResponseType(typeof(PurchasePlanResponse), 200)]
    public async Task<IActionResult> Purchase([FromBody] PurchasePlanRequest request)
    {
        var result = await planService.PurchasePlanAsync(GetUserId(), GetTenantId(), request);
        return Ok(result);
    }

    /// <summary>
    /// Cancel the current active subscription. The plan stays active until its
    /// expiry date but will not auto-renew. Returns 404 when no active plan exists.
    /// </summary>
    [HttpPost("users/me/plan/cancel")]
    [ProducesResponseType(204)]
    [ProducesResponseType(404)]
    public async Task<IActionResult> Cancel()
    {
        try
        {
            await planService.CancelPlanAsync(GetUserId());
            return NoContent();
        }
        catch (KeyNotFoundException ex)
        {
            return NotFound(new { error = ex.Message });
        }
    }

    private Guid GetUserId() => Guid.Parse(User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value
        ?? User.FindFirst("sub")?.Value ?? throw new UnauthorizedAccessException());

    private Guid GetTenantId() => Guid.Parse(User.FindFirst("tenant_id")?.Value
        ?? throw new UnauthorizedAccessException());

    private Guid? GetTenantIdOrNull() => User.FindFirst("tenant_id")?.Value is { } t && Guid.TryParse(t, out var id)
        ? id : null;
}
