using System.Security.Claims;
using FastEndpoints;
using FluentValidation;
using Microsoft.EntityFrameworkCore;
using TrackQrApi.Data;
using TrackQrApi.Features.Auth.Common;
using TrackQrApi.Features.Links.Common;
using TrackQrApi.Features.Plans.Services;
using TrackQrApi.Models;

namespace TrackQrApi.Features.Links.Endpoints;

public class CreateLinkRequest
{
    public Guid WorkspaceId { get; set; }
    public string DestinationUrl { get; set; } = string.Empty;
    public string? Slug { get; set; }
    public string? Title { get; set; }
    public Guid? ProjectId { get; set; }
}

public class CreateLinkValidator : Validator<CreateLinkRequest>
{
    public CreateLinkValidator()
    {
        RuleFor(x => x.DestinationUrl)
            .NotEmpty().WithMessage("Destination URL is required")
            .MaximumLength(2048).WithMessage("Destination URL must not exceed 2048 characters")
            .Must(BeAValidUrl).WithMessage("Destination URL must be a valid URL");

        RuleFor(x => x.Slug)
            .MaximumLength(50).WithMessage("Slug must not exceed 50 characters")
            .Matches(@"^[a-zA-Z0-9_-]*$")
            .WithMessage("Slug can only contain letters, numbers, hyphens, and underscores")
            .When(x => !string.IsNullOrEmpty(x.Slug));

        RuleFor(x => x.Title)
            .MaximumLength(255).WithMessage("Title must not exceed 255 characters");
    }

    private static bool BeAValidUrl(string url)
    {
        return Uri.TryCreate(url, UriKind.Absolute, out var uri)
               && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps);
    }
}

public class CreateLinkEndpoint(AppDbContext db, IPlanLimitsService planLimits)
    : Endpoint<CreateLinkRequest, LinkResponse>
{
    public override void Configure()
    {
        Post("/workspaces/{WorkspaceId}/links");
    }

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

        // Verify workspace ownership
        var workspaceExists = await db.Workspaces
            .AnyAsync(w => w.Id == req.WorkspaceId && w.OwnerUserId == userId, ct);

        if (!workspaceExists)
        {
            await HttpContext.Response.SendAsync(new MessageResponse("Workspace not found"), 404, cancellation: ct);
            return;
        }

        // Check plan limits
        if (!await planLimits.CanCreateLinkAsync(req.WorkspaceId, ct))
        {
            await HttpContext.Response.SendAsync(
                new MessageResponse("Link limit reached. Please upgrade your plan to create more links."),
                402,
                cancellation: ct);
            return;
        }

        // Verify project belongs to workspace if specified
        if (req.ProjectId.HasValue)
        {
            var projectExists = await db.Projects
                .AnyAsync(p => p.Id == req.ProjectId.Value && p.WorkspaceId == req.WorkspaceId, ct);

            if (!projectExists)
            {
                await HttpContext.Response.SendAsync(new MessageResponse("Project not found"), 404, cancellation: ct);
                return;
            }
        }

        // Generate or validate slug
        var slug = req.Slug;
        if (string.IsNullOrEmpty(slug))
        {
            // Auto-generate unique slug
            do
            {
                slug = SlugGenerator.Generate();
            } while (await db.ShortLinks.AnyAsync(l => l.Slug == slug && l.DomainId == null, ct));
        }
        else
        {
            // Check if custom slug is already taken (on default domain)
            var slugExists = await db.ShortLinks
                .AnyAsync(l => l.Slug == slug && l.DomainId == null, ct);

            if (slugExists)
            {
                await HttpContext.Response.SendAsync(new MessageResponse("Slug is already taken"), 409,
                    cancellation: ct);
                return;
            }
        }

        var now = DateTime.UtcNow;
        var link = new ShortLink
        {
            Id = Guid.NewGuid(),
            WorkspaceId = req.WorkspaceId,
            ProjectId = req.ProjectId,
            DomainId = null, // Default domain for now
            Slug = slug,
            DestinationUrl = req.DestinationUrl,
            Title = req.Title,
            Status = ShortLinkStatus.Active,
            CreatedAt = now,
            UpdatedAt = now
        };

        db.ShortLinks.Add(link);
        await db.SaveChangesAsync(ct);

        var response = new LinkResponse(
            link.Id,
            link.WorkspaceId,
            link.ProjectId,
            link.DomainId,
            link.Slug,
            link.DestinationUrl,
            link.Title,
            link.Status.ToString(),
            link.ExpiresAt,
            link.PasswordHash != null,
            link.CreatedAt,
            link.UpdatedAt
        );

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