using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace JobTrackerApi.Controllers;

[ApiController]
[Route("api/ai/usage")]
[Authorize(AuthenticationSchemes = "local")]
public sealed class AiUsageController : ControllerBase
{
    private readonly UserManager<ApplicationUser> _users;
    private readonly JobTrackerContext _db;
    private readonly AiUsageMeter? _usage;

    public AiUsageController(UserManager<ApplicationUser> users, JobTrackerContext db, AiUsageMeter? usage = null)
    {
        _users = users;
        _db = db;
        _usage = usage;
    }

    public sealed record UsagePeriodDto(int Calls, long InputCharacters, long OutputCharacters, long EstimatedTokens);
    public sealed record UsageDto(UsagePeriodDto CurrentMonth, UsagePeriodDto AllTime, string Plan, int MonthlyCallLimit, long MonthlyTokenLimit, long StorageUsedBytes, long StorageLimitBytes);

    [HttpGet]
    public async Task<ActionResult<UsageDto>> Get(CancellationToken cancellationToken)
    {
        var user = await _users.GetUserAsync(User);
        if (user is null) return Unauthorized();

        var roles = await _users.GetRolesAsync(user);
        var entitlements = AccountPlans.ForRoles(roles);
        var meter = _usage ?? new AiUsageMeter(_db, TimeProvider.System);
        var currentMonth = ToDto(await meter.CurrentMonthAsync(user.Id, cancellationToken));
        return Ok(new UsageDto(
            currentMonth,
            ToDto(await meter.AllTimeAsync(user.Id, cancellationToken)),
            AccountPlans.Name(entitlements),
            entitlements.MonthlyAiCalls,
            entitlements.MonthlyAiTokens,
            await _db.Attachments.Where(x => x.JobApplication.OwnerUserId == user.Id)
                .SumAsync(x => (long?)x.FileSize, cancellationToken) ?? 0,
            entitlements.StorageBytes));
    }

    private static UsagePeriodDto ToDto(AiUsageTotals totals)
        => new(totals.Calls, totals.InputCharacters, totals.OutputCharacters, totals.EstimatedTokens);
}
