using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using StorageService.Domain.AggregatesModel.FileAggregate;
using StorageService.Domain.AggregatesModel.FileVersionAggregate;
using StorageService.Infrastructure.Storage;
using Swashbuckle.AspNetCore.Annotations;
using System.Security.Claims;

namespace StorageService.API.Controllers;

/// <summary>
/// EN: Controller for file versioning operations.
/// VI: Controller cho các thao tác versioning file.
/// </summary>
[ApiController]
[Route("api/v1/storage/files/{fileId:guid}/versions")]
[Authorize]
[Produces("application/json")]
public class FileVersioningController : ControllerBase
{
    private readonly IFileRepository _fileRepository;
    private readonly IFileVersionRepository _fileVersionRepository;
    private readonly IStorageProviderFactory _storageProviderFactory;
    private readonly ILogger<FileVersioningController> _logger;

    public FileVersioningController(
        IFileRepository fileRepository,
        IFileVersionRepository fileVersionRepository,
        IStorageProviderFactory storageProviderFactory,
        ILogger<FileVersioningController> logger)
    {
        _fileRepository = fileRepository;
        _fileVersionRepository = fileVersionRepository;
        _storageProviderFactory = storageProviderFactory;
        _logger = logger;
    }

    /// <summary>
    /// EN: Get all versions of a file.
    /// VI: Lấy tất cả phiên bản của file.
    /// </summary>
    [HttpGet]
    [SwaggerOperation(Summary = "Get file versions", Description = "Get all versions of a file")]
    [SwaggerResponse(200, "Versions retrieved", typeof(ApiResponse<IEnumerable<FileVersionDto>>))]
    [SwaggerResponse(404, "File not found")]
    public async Task<ActionResult<ApiResponse<IEnumerable<FileVersionDto>>>> GetVersions([FromRoute] Guid fileId)
    {
        var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        if (string.IsNullOrEmpty(userId))
        {
            return Unauthorized(new ApiResponse<IEnumerable<FileVersionDto>> { Success = false, Error = "User ID not found" });
        }

        // EN: Verify file exists and user owns it / VI: Kiểm tra file tồn tại và user sở hữu
        var file = await _fileRepository.GetByIdAsync(fileId);
        if (file == null || file.UserId != userId)
        {
            return NotFound(new ApiResponse<IEnumerable<FileVersionDto>> { Success = false, Error = "File not found" });
        }

        var versions = await _fileVersionRepository.GetByFileIdAsync(fileId);
        var versionDtos = versions.Select(v => new FileVersionDto(
            v.Id,
            v.FileId,
            v.VersionNumber,
            v.SizeBytes,
            v.ContentType,
            v.Checksum,
            v.CreatedAt,
            v.CreatedBy,
            v.Comment,
            v.IsCurrent));

        return Ok(new ApiResponse<IEnumerable<FileVersionDto>>
        {
            Success = true,
            Data = versionDtos
        });
    }

    /// <summary>
    /// EN: Get download URL for a specific version.
    /// VI: Lấy URL tải xuống cho phiên bản cụ thể.
    /// </summary>
    [HttpGet("{versionId:guid}/download")]
    [SwaggerOperation(Summary = "Download version", Description = "Get download URL for a specific version")]
    [SwaggerResponse(200, "Download URL generated", typeof(ApiResponse<DownloadVersionResponse>))]
    [SwaggerResponse(404, "Version not found")]
    public async Task<ActionResult<ApiResponse<DownloadVersionResponse>>> DownloadVersion(
        [FromRoute] Guid fileId,
        [FromRoute] Guid versionId)
    {
        var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        if (string.IsNullOrEmpty(userId))
        {
            return Unauthorized(new ApiResponse<DownloadVersionResponse> { Success = false, Error = "User ID not found" });
        }

        // EN: Verify file exists and user owns it / VI: Kiểm tra file tồn tại và user sở hữu
        var file = await _fileRepository.GetByIdAsync(fileId);
        if (file == null || file.UserId != userId)
        {
            return NotFound(new ApiResponse<DownloadVersionResponse> { Success = false, Error = "File not found" });
        }

        var version = await _fileVersionRepository.GetByIdAsync(versionId);
        if (version == null || version.FileId != fileId)
        {
            return NotFound(new ApiResponse<DownloadVersionResponse> { Success = false, Error = "Version not found" });
        }

        // EN: Generate pre-signed URL / VI: Tạo pre-signed URL
        var provider = _storageProviderFactory.GetProvider(file.Provider);
        var downloadUrl = await provider.GetPreSignedDownloadUrlAsync(
            file.BucketName,
            version.ObjectKey,
            3600); // 1 hour

        return Ok(new ApiResponse<DownloadVersionResponse>
        {
            Success = true,
            Data = new DownloadVersionResponse(downloadUrl, version.VersionNumber, file.FileName)
        });
    }

    /// <summary>
    /// EN: Restore a file to a specific version.
    /// VI: Khôi phục file về phiên bản cụ thể.
    /// </summary>
    [HttpPost("{versionId:guid}/restore")]
    [SwaggerOperation(Summary = "Restore version", Description = "Restore file to a specific version")]
    [SwaggerResponse(200, "Version restored", typeof(ApiResponse<RestoreVersionResponse>))]
    [SwaggerResponse(404, "Version not found")]
    public async Task<ActionResult<ApiResponse<RestoreVersionResponse>>> RestoreVersion(
        [FromRoute] Guid fileId,
        [FromRoute] Guid versionId)
    {
        var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        if (string.IsNullOrEmpty(userId))
        {
            return Unauthorized(new ApiResponse<RestoreVersionResponse> { Success = false, Error = "User ID not found" });
        }

        // EN: Verify file exists and user owns it / VI: Kiểm tra file tồn tại và user sở hữu
        var file = await _fileRepository.GetByIdAsync(fileId);
        if (file == null || file.UserId != userId)
        {
            return NotFound(new ApiResponse<RestoreVersionResponse> { Success = false, Error = "File not found" });
        }

        var versionToRestore = await _fileVersionRepository.GetByIdAsync(versionId);
        if (versionToRestore == null || versionToRestore.FileId != fileId)
        {
            return NotFound(new ApiResponse<RestoreVersionResponse> { Success = false, Error = "Version not found" });
        }

        // EN: Unmark current version / VI: Bỏ đánh dấu version hiện tại
        var currentVersion = await _fileVersionRepository.GetCurrentVersionAsync(fileId);
        if (currentVersion != null)
        {
            currentVersion.UnmarkAsCurrent();
            _fileVersionRepository.Update(currentVersion);
        }

        // EN: Mark restored version as current / VI: Đánh dấu version được khôi phục là hiện tại
        versionToRestore.MarkAsCurrent();
        _fileVersionRepository.Update(versionToRestore);

        // EN: Update file metadata with restored version's data / VI: Cập nhật metadata file với dữ liệu của version được khôi phục
        file.UpdateFromVersion(versionToRestore.ObjectKey, versionToRestore.SizeBytes, versionToRestore.ContentType);
        _fileRepository.Update(file);

        await _fileVersionRepository.UnitOfWork.SaveEntitiesAsync();

        _logger.LogInformation(
            "File {FileId} restored to version {VersionNumber}",
            fileId, versionToRestore.VersionNumber);

        return Ok(new ApiResponse<RestoreVersionResponse>
        {
            Success = true,
            Data = new RestoreVersionResponse(versionToRestore.VersionNumber, "File restored successfully")
        });
    }
}

#region DTOs

/// <summary>
/// EN: DTO for file version.
/// VI: DTO cho phiên bản file.
/// </summary>
public record FileVersionDto(
    Guid Id,
    Guid FileId,
    int VersionNumber,
    long SizeBytes,
    string ContentType,
    string? Checksum,
    DateTime CreatedAt,
    string CreatedBy,
    string? Comment,
    bool IsCurrent);

/// <summary>
/// EN: Response for version download.
/// VI: Response cho tải xuống version.
/// </summary>
public record DownloadVersionResponse(
    string DownloadUrl,
    int VersionNumber,
    string FileName);

/// <summary>
/// EN: Response for version restore.
/// VI: Response cho khôi phục version.
/// </summary>
public record RestoreVersionResponse(
    int RestoredVersionNumber,
    string Message);

#endregion
