using PlotLine.Data;
using PlotLine.Models;

namespace PlotLine.Services;

public sealed class AccountDeletionService(
    IUserRepository users,
    IProjectRepository projects,
    ISubscriptionService subscriptions,
    IHardDeleteFileCleanupService fileCleanup,
    ILogger<AccountDeletionService> logger) : IAccountDeletionService
{
    public async Task<AccountDeletionResult> HardDeleteAccountAsync(int userId)
    {
        var user = await users.GetByIdAsync(userId);
        if (user is null)
        {
            logger.LogWarning("Account hard delete requested for missing user {UserID}.", userId);
            return AccountDeletionResult.MissingUser();
        }

        if (await subscriptions.HasPaidBillingRiskAsync(userId))
        {
            logger.LogWarning("Account hard delete blocked for user {UserID}: paid billing risk exists.", userId);
            return AccountDeletionResult.PaidSubscriptionBlocked();
        }

        var deletedProjects = 0;
        var deletedFiles = 0;
        var missingFiles = 0;
        var failedFiles = 0;

        var ownedProjects = await projects.ListOwnedForAccountDeletionAsync(userId);
        logger.LogInformation("Account hard delete started for user {UserID} with {OwnedProjectCount} owned projects.", userId, ownedProjects.Count);

        foreach (var project in ownedProjects)
        {
            IReadOnlyList<string> projectFilePaths;
            try
            {
                projectFilePaths = await projects.ListHardDeleteFilePathsForAccountDeletionAsync(project.ProjectID, userId);
                await projects.HardDeleteForAccountDeletionAsync(project.ProjectID, userId);
                deletedProjects++;
                logger.LogInformation("Account hard delete removed project {ProjectID} for user {UserID}. {FilePathCount} file paths queued for cleanup.",
                    project.ProjectID,
                    userId,
                    projectFilePaths.Count);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Account hard delete failed while deleting project {ProjectID} for user {UserID}. Account deletion stopped.",
                    project.ProjectID,
                    userId);
                return AccountDeletionResult.Failure("The account could not be deleted. No further account data was removed.");
            }

            var projectCleanup = fileCleanup.DeleteFiles("account project hard delete", project.ProjectID, projectFilePaths);
            deletedFiles += projectCleanup.Deleted;
            missingFiles += projectCleanup.Missing;
            failedFiles += projectCleanup.Failed;
        }

        IReadOnlyList<string> userFilePaths;
        try
        {
            userFilePaths = await users.ListHardDeleteFilePathsAsync(userId);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Account hard delete could not list remaining user-level files for user {UserID}. Account deletion stopped.", userId);
            return AccountDeletionResult.Failure("The account could not be deleted. No further account data was removed.");
        }

        var userCleanup = fileCleanup.DeleteFiles("account user file hard delete", userId, userFilePaths);
        deletedFiles += userCleanup.Deleted;
        missingFiles += userCleanup.Missing;
        failedFiles += userCleanup.Failed;

        try
        {
            var deleted = await users.HardDeleteAccountDataAsync(userId);
            if (!deleted)
            {
                logger.LogError("Account hard delete failed to remove the AppUser row for user {UserID}.", userId);
                return AccountDeletionResult.Failure("The account could not be deleted.");
            }
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Account hard delete failed while removing remaining user data for user {UserID}.", userId);
            return AccountDeletionResult.Failure("The account could not be deleted.");
        }

        if (failedFiles > 0)
        {
            logger.LogWarning("Account hard delete completed for user {UserID}, but file cleanup had {FailedFileCount} failures, {DeletedFileCount} deleted files, and {MissingFileCount} missing files.",
                userId,
                failedFiles,
                deletedFiles,
                missingFiles);
        }
        else
        {
            logger.LogInformation("Account hard delete completed for user {UserID}: {DeletedProjectCount} projects, {DeletedFileCount} files deleted, {MissingFileCount} files missing.",
                userId,
                deletedProjects,
                deletedFiles,
                missingFiles);
        }

        return AccountDeletionResult.Success(deletedProjects, deletedFiles, missingFiles, failedFiles);
    }
}
