using System.IO;
using System.Net.Http;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace CMSMicroservice.WebApi.Controllers;

/// <summary>
/// سرویس عمومی سرو تصاویر — فایل‌ها مستقیماً از پوشه Uploads سرو می‌شوند.
/// اگر فایل محلی وجود نداشت، از FMS قدیمی (dl.afrino.co) دانلود و کش می‌شود.
/// </summary>
[ApiController]
[AllowAnonymous]
[ApiExplorerSettings(GroupName = "cms")]
public class UploadsController : ControllerBase
{
    private readonly string _uploadRoot;
    private readonly string _fmsBaseUrl;
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly ILogger<UploadsController> _logger;
    private readonly FileExtensionContentTypeProvider _contentTypeProvider = new();

    // حداکثر طول مسیر مجاز (جلوگیری از path traversal)
    private const int MaxPathLength = 500;

    public UploadsController(
        IConfiguration configuration,
        IHttpClientFactory httpClientFactory,
        ILogger<UploadsController> logger)
    {
        _httpClientFactory = httpClientFactory;
        _logger = logger;

        _uploadRoot = configuration["FileStorage:UploadPath"]
                      ?? Path.Combine(AppContext.BaseDirectory, "Uploads");

        _fmsBaseUrl = configuration["FMS:Address"]?.TrimEnd('/') ?? string.Empty;
    }

    /// <summary>
    /// سرو عمومی فایل از پوشه Uploads.
    /// اگر فایل محلی وجود نداشت و FMS تنظیم شده باشد، از FMS دانلود و کش می‌شود.
    /// </summary>
    /// <param name="path">مسیر نسبی فایل (مثلاً blog/image.jpg)</param>
    [HttpGet("uploads/{**path}")]
    [ResponseCache(Duration = 86400, Location = ResponseCacheLocation.Any)] // کش مرورگر ۲۴ ساعت
    public async Task<IActionResult> GetFile(string path)
    {
        // ── اعتبارسنجی مسیر ──
        if (string.IsNullOrWhiteSpace(path) || path.Length > MaxPathLength)
            return BadRequest("مسیر نامعتبر");

        // جلوگیری از path traversal
        if (path.Contains("..") || path.Contains('\\'))
            return BadRequest("مسیر نامعتبر");

        var sanitizedPath = path.TrimStart('/');
        var fullPath = Path.GetFullPath(Path.Combine(_uploadRoot, sanitizedPath));

        // اطمینان از اینکه مسیر درون _uploadRoot باقی می‌ماند
        if (!fullPath.StartsWith(Path.GetFullPath(_uploadRoot), StringComparison.OrdinalIgnoreCase))
            return BadRequest("مسیر نامعتبر");

        // ── سرو فایل محلی ──
        if (System.IO.File.Exists(fullPath))
            return ServeFile(fullPath);

        // ── Fallback: دانلود از FMS قدیمی ──
        if (string.IsNullOrWhiteSpace(_fmsBaseUrl))
        {
            _logger.LogWarning("File not found locally and no FMS configured: {Path}", sanitizedPath);
            return NotFound();
        }

        var downloaded = await TryDownloadFromFmsAsync(sanitizedPath, fullPath);
        if (downloaded)
        {
            _logger.LogInformation("Downloaded and cached from FMS: {Path}", sanitizedPath);
            return ServeFile(fullPath);
        }

        return NotFound();
    }

    // ────────────────────────────────────────────────────
    //  سرو فایل با Content-Type مناسب
    // ────────────────────────────────────────────────────
    private IActionResult ServeFile(string fullPath)
    {
        if (!_contentTypeProvider.TryGetContentType(fullPath, out var contentType))
            contentType = "application/octet-stream";

        var stream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read);
        return File(stream, contentType, enableRangeProcessing: true);
    }

    // ────────────────────────────────────────────────────
    //  دانلود از FMS قدیمی و ذخیره محلی
    // ────────────────────────────────────────────────────
    private async Task<bool> TryDownloadFromFmsAsync(string relativePath, string localPath)
    {
        try
        {
            var fmsUrl = $"{_fmsBaseUrl}/{relativePath}";
            _logger.LogInformation("Attempting FMS download: {Url}", fmsUrl);

            using var client = _httpClientFactory.CreateClient("FMS");
            using var response = await client.GetAsync(fmsUrl, HttpCompletionOption.ResponseHeadersRead);

            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("FMS returned {Status} for {Url}", response.StatusCode, fmsUrl);
                return false;
            }

            // بررسی Content-Type — فقط فایل‌های تصویری/مجاز
            var mediaType = response.Content.Headers.ContentType?.MediaType ?? string.Empty;
            if (!IsAllowedMediaType(mediaType))
            {
                _logger.LogWarning("FMS returned disallowed content type {Type} for {Url}", mediaType, fmsUrl);
                return false;
            }

            // ذخیره روی دیسک
            var directory = Path.GetDirectoryName(localPath)!;
            Directory.CreateDirectory(directory);

            await using var fileStream = new FileStream(localPath, FileMode.Create, FileAccess.Write, FileShare.None);
            await response.Content.CopyToAsync(fileStream);

            _logger.LogInformation("Cached FMS file locally: {Path} ({Size} bytes)", relativePath, fileStream.Length);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to download from FMS: {Path}", relativePath);
            return false;
        }
    }

    private static bool IsAllowedMediaType(string mediaType)
    {
        return mediaType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)
               || mediaType is "application/pdf"
                            or "application/octet-stream";
    }
}
