using System.Security.Claims;
using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using TrackQrApi.Data;
using TrackQrApi.Features.Auth.Common;
using TrackQrApi.Models;

namespace TrackQrApi.Features.QRCodes.Endpoints;

public class GetQRCodeAnalyticsRequest
{
    public Guid WorkspaceId { get; set; }
    public Guid Id { get; set; }
    public string Period { get; set; } = "7d";
}

public record QRCodeAnalyticsSummary(
    int TotalScans,
    int UniqueVisitors
);

public record QRCodeTimeSeriesPoint(
    string Date,
    int Scans
);

public record QRCodeAnalyticsResponse(
    Guid QRCodeId,
    string Name,
    string? LinkSlug,
    QRCodeAnalyticsSummary Summary,
    List<QRCodeTimeSeriesPoint> TimeSeries,
    Dictionary<string, int> DeviceBreakdown,
    Dictionary<string, int> ReferrerBreakdown,
    Dictionary<string, int> CountryBreakdown
);

public class GetQRCodeAnalyticsEndpoint(AppDbContext db)
    : Endpoint<GetQRCodeAnalyticsRequest, QRCodeAnalyticsResponse>
{
    public override void Configure()
    {
        Get("/workspaces/{WorkspaceId}/qrcodes/{Id}/analytics");
    }

    public override async Task HandleAsync(GetQRCodeAnalyticsRequest req, CancellationToken ct)
    {
        var userId = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);

        var qrCode = await db.QrCodeDesigns
            .Include(q => q.ShortLink)
            .Where(q => q.Id == req.Id && q.WorkspaceId == req.WorkspaceId && q.Workspace.OwnerUserId == userId)
            .FirstOrDefaultAsync(ct);

        if (qrCode == null)
        {
            await HttpContext.Response.SendAsync(new MessageResponse("QR code not found"), 404, cancellation: ct);
            return;
        }

        var startDate = GetStartDate(req.Period);

        var events = await db.Events
            .Where(e => e.QRCodeId == req.Id && e.Type == EventType.Scan && e.Timestamp >= startDate)
            .ToListAsync(ct);

        var summary = new QRCodeAnalyticsSummary(
            events.Count,
            events.Select(e => e.IpHash).Distinct().Count()
        );

        var timeSeries = events
            .GroupBy(e => e.Timestamp.Date)
            .OrderBy(g => g.Key)
            .Select(g => new QRCodeTimeSeriesPoint(
                g.Key.ToString("yyyy-MM-dd"),
                g.Count()
            ))
            .ToList();

        var deviceBreakdown = events
            .Where(e => !string.IsNullOrEmpty(e.DeviceType))
            .GroupBy(e => e.DeviceType!)
            .ToDictionary(g => g.Key, g => g.Count());

        var referrerBreakdown = events
            .Where(e => !string.IsNullOrEmpty(e.Referrer))
            .GroupBy(e => GetReferrerDomain(e.Referrer!))
            .OrderByDescending(g => g.Count())
            .Take(10)
            .ToDictionary(g => g.Key, g => g.Count());

        var countryBreakdown = events
            .Where(e => !string.IsNullOrEmpty(e.CountryCode))
            .GroupBy(e => e.CountryCode!)
            .OrderByDescending(g => g.Count())
            .Take(10)
            .ToDictionary(g => g.Key, g => g.Count());

        var response = new QRCodeAnalyticsResponse(
            qrCode.Id,
            qrCode.Name,
            qrCode.ShortLink?.Slug,
            summary,
            timeSeries,
            deviceBreakdown,
            referrerBreakdown,
            countryBreakdown
        );

        await HttpContext.Response.SendAsync(response, cancellation: ct);
    }

    private static DateTime GetStartDate(string period)
    {
        return period switch
        {
            "24h" => DateTime.UtcNow.AddHours(-24),
            "7d" => DateTime.UtcNow.AddDays(-7),
            "30d" => DateTime.UtcNow.AddDays(-30),
            "all" => DateTime.MinValue,
            _ => DateTime.UtcNow.AddDays(-7)
        };
    }

    private static string GetReferrerDomain(string referrer)
    {
        try
        {
            var uri = new Uri(referrer);
            return uri.Host;
        }
        catch
        {
            return referrer;
        }
    }
}