using System.ComponentModel.DataAnnotations;
using PlotLine.Models;

namespace PlotLine.ViewModels;

public sealed class ManageAccountViewModel
{
    public AppUser User { get; set; } = new();
    public UserSubscriptionDetail? Subscription { get; set; }
    public TrialVisibilityViewModel? Trial { get; set; }
    public bool HasPaidBillingRisk { get; set; }
}

public sealed class ManageSubscriptionViewModel
{
    public AppUser User { get; set; } = new();
    public UserSubscriptionDetail? CurrentSubscription { get; set; }
    public TrialVisibilityViewModel? Trial { get; set; }
    public SubscriptionUsageSummary? Usage { get; set; }
    public IReadOnlyList<SubscriptionLevel> AvailableLevels { get; set; } = [];
}

public sealed class TrialVisibilityViewModel
{
    public const int TrialDurationDays = 30;

    public string PlanName { get; init; } = string.Empty;
    public DateTime StartDateUtc { get; init; }
    public DateTime ExpiryDateUtc { get; init; }
    public int DaysRemaining { get; init; }
    public int DaysElapsed { get; init; }
    public int ProgressPercentage { get; init; }
    public bool IsExpired { get; init; }
    public int? WarningThresholdDays { get; init; }

    public string StatusLabel => IsExpired
        ? "Trial expired"
        : DaysRemaining == 1 ? "1 day remaining" : $"{DaysRemaining} days remaining";

    public string WarningCssClass => WarningThresholdDays switch
    {
        <= 1 => "trial-status--one-day",
        <= 3 => "trial-status--three-days",
        <= 7 => "trial-status--seven-days",
        <= 14 => "trial-status--fourteen-days",
        _ => "trial-status--steady"
    };

    public static TrialVisibilityViewModel? FromSubscription(UserSubscriptionDetail? subscription, DateTime utcNow)
    {
        if (subscription is null)
        {
            return null;
        }

        var isTrialPlan = subscription.IsTrial
            || (!subscription.RequiresStripeSubscription && string.IsNullOrWhiteSpace(subscription.StripeSubscriptionId));
        if (!isTrialPlan)
        {
            return null;
        }

        var start = subscription.StartDateUTC;
        var expiry = subscription.TrialExpiryDateUTC ?? start.AddDays(TrialDurationDays);
        var totalDays = Math.Max(1, (int)Math.Ceiling((expiry - start).TotalDays));
        var rawRemaining = (int)Math.Ceiling((expiry - utcNow).TotalDays);
        var daysRemaining = Math.Max(0, rawRemaining);
        var daysElapsed = Math.Clamp(totalDays - daysRemaining, 0, totalDays);
        var progress = Math.Clamp((int)Math.Round(daysElapsed * 100m / totalDays), 0, 100);

        return new TrialVisibilityViewModel
        {
            PlanName = subscription.DisplayName,
            StartDateUtc = start,
            ExpiryDateUtc = expiry,
            DaysRemaining = daysRemaining,
            DaysElapsed = daysElapsed,
            ProgressPercentage = progress,
            IsExpired = utcNow >= expiry,
            WarningThresholdDays = daysRemaining <= 1 ? 1
                : daysRemaining <= 3 ? 3
                : daysRemaining <= 7 ? 7
                : daysRemaining <= 14 ? 14
                : null
        };
    }
}

public sealed class PricingViewModel
{
    public IReadOnlyList<SubscriptionLevel> Plans { get; set; } = [];
    public int? CurrentSubscriptionLevelID { get; set; }
    public bool IsSignedIn { get; set; }
}

public sealed class PublicPageViewModel
{
    public string SupportEmail { get; set; } = "support@plotdirector.com";
    public string LastUpdated { get; set; } = "June 7, 2026";
}

public sealed class RegisterViewModel
{
    [Required(ErrorMessage = "Enter your email address.")]
    [EmailAddress(ErrorMessage = "Enter a valid email address.")]
    [StringLength(256, ErrorMessage = "Email must be 256 characters or fewer.")]
    public string Email { get; set; } = string.Empty;

    [Required(ErrorMessage = "Enter a display name.")]
    [StringLength(200, ErrorMessage = "Display name must be 200 characters or fewer.")]
    public string DisplayName { get; set; } = string.Empty;

    [Required(ErrorMessage = "Enter a password.")]
    [StringLength(200, MinimumLength = 12, ErrorMessage = "Password must be at least 12 characters.")]
    [DataType(DataType.Password)]
    public string Password { get; set; } = string.Empty;

    [Required(ErrorMessage = "Confirm your password.")]
    [DataType(DataType.Password)]
    [Compare(nameof(Password), ErrorMessage = "Passwords do not match.")]
    public string ConfirmPassword { get; set; } = string.Empty;
}

public sealed class LoginViewModel
{
    [Required(ErrorMessage = "Enter your email address.")]
    [EmailAddress(ErrorMessage = "Enter a valid email address.")]
    [StringLength(256, ErrorMessage = "Email must be 256 characters or fewer.")]
    public string Email { get; set; } = string.Empty;

    [Required(ErrorMessage = "Enter your password.")]
    [DataType(DataType.Password)]
    public string Password { get; set; } = string.Empty;

    public bool RememberMe { get; set; }

    public string? ReturnUrl { get; set; }

    public bool IsCompanionLogin { get; set; }
}

public sealed class ForgotPasswordViewModel
{
    [Required(ErrorMessage = "Enter your email address.")]
    [EmailAddress(ErrorMessage = "Enter a valid email address.")]
    [StringLength(256, ErrorMessage = "Email must be 256 characters or fewer.")]
    public string Email { get; set; } = string.Empty;
}

public sealed class ResendVerificationEmailViewModel
{
    [Required(ErrorMessage = "Enter your email address.")]
    [EmailAddress(ErrorMessage = "Enter a valid email address.")]
    [StringLength(256, ErrorMessage = "Email must be 256 characters or fewer.")]
    public string Email { get; set; } = string.Empty;
}

public sealed class ResetPasswordViewModel
{
    [Required(ErrorMessage = "Password reset token is missing.")]
    public Guid Token { get; set; }

    [Required(ErrorMessage = "Enter a new password.")]
    [StringLength(200, MinimumLength = 12, ErrorMessage = "Password must be at least 12 characters.")]
    [DataType(DataType.Password)]
    public string Password { get; set; } = string.Empty;

    [Required(ErrorMessage = "Confirm your new password.")]
    [DataType(DataType.Password)]
    [Compare(nameof(Password), ErrorMessage = "Passwords do not match.")]
    public string ConfirmPassword { get; set; } = string.Empty;
}

public sealed class AccountStatusViewModel
{
    public bool Success { get; set; }
    public string Title { get; set; } = string.Empty;
    public string Message { get; set; } = string.Empty;
}

public sealed class TwoFactorCodeViewModel
{
    [Required(ErrorMessage = "Enter the code from your authenticator app.")]
    [StringLength(20, ErrorMessage = "Authentication code is too long.")]
    public string Code { get; set; } = string.Empty;

    public string? ReturnUrl { get; set; }
}

public sealed class TwoFactorRecoveryViewModel
{
    [Required(ErrorMessage = "Enter a recovery code.")]
    [StringLength(20, ErrorMessage = "Recovery code is too long.")]
    public string RecoveryCode { get; set; } = string.Empty;

    public string? ReturnUrl { get; set; }
}

public sealed class EnableTwoFactorViewModel
{
    [Required(ErrorMessage = "Authenticator secret is missing.")]
    public string SecretKey { get; set; } = string.Empty;

    public string QrCodeUri { get; set; } = string.Empty;

    public string? QrCodeImageDataUri { get; set; }

    [Required(ErrorMessage = "Enter the code from your authenticator app.")]
    [StringLength(20, ErrorMessage = "Authentication code is too long.")]
    public string Code { get; set; } = string.Empty;
}

public sealed class DisableTwoFactorViewModel
{
    [Required(ErrorMessage = "Enter your current password.")]
    [DataType(DataType.Password)]
    public string CurrentPassword { get; set; } = string.Empty;
}

public sealed class RecoveryCodesViewModel
{
    public IReadOnlyList<string> RecoveryCodes { get; set; } = Array.Empty<string>();
    public bool HasNewCodes => RecoveryCodes.Any();
}

public sealed class ChangePasswordViewModel
{
    [Required(ErrorMessage = "Enter your current password.")]
    [DataType(DataType.Password)]
    public string CurrentPassword { get; set; } = string.Empty;

    [Required(ErrorMessage = "Enter a new password.")]
    [StringLength(200, MinimumLength = 12, ErrorMessage = "Password must be at least 12 characters.")]
    [DataType(DataType.Password)]
    public string NewPassword { get; set; } = string.Empty;

    [Required(ErrorMessage = "Confirm your new password.")]
    [DataType(DataType.Password)]
    [Compare(nameof(NewPassword), ErrorMessage = "Passwords do not match.")]
    public string ConfirmNewPassword { get; set; } = string.Empty;
}
