using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.Models.Media;
using Lada.Framework.DTO.Results.Media;
using Lada.Framework.Infrastructures.AppSettings;
using Lada.Framework.Infrastructures.Helpers;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;

namespace Lada.Framework.Infrastructures.Services
{
    public interface IDocumentService
    {
        /// <summary>
        /// Xử lý và lưu tài liệu, trả về URL
        /// </summary>
        /// <param name="file">File tài liệu cần xử lý</param>
        /// <param name="documentType">Loại tài liệu (để tổ chức thư mục)</param>
        /// <param name="documentFormat">Định dạng tài liệu</param>
        /// <returns>Kết quả xử lý tài liệu với URL</returns>
        Task<DocumentProcessResult> ProcessDocumentAsync(IFormFile file, DocumentType documentType, DocumentFormat documentFormat);

        /// <summary>
        /// Xử lý và lưu tài liệu với metadata vào database (optional)
        /// </summary>
        /// <param name="file">File tài liệu cần xử lý</param>
        /// <param name="options">Tùy chọn lưu tài liệu và metadata</param>
        /// <returns>Kết quả xử lý tài liệu với metadata</returns>
        Task<DocumentProcessResult> ProcessAndSaveAsync(IFormFile file, DocumentSaveOptions options);

        /// <summary>
        /// Validate tài liệu bằng header validation
        /// </summary>
        /// <param name="file">File cần validate</param>
        /// <param name="expectedFormat">Định dạng mong đợi</param>
        /// <returns>True nếu là tài liệu hợp lệ</returns>
        Task<bool> ValidateDocumentAsync(IFormFile file, DocumentFormat expectedFormat);

        /// <summary>
        /// Chuyển đổi SystemPath thành URL hiển thị
        /// </summary>
        /// <param name="systemPath">Đường dẫn hệ thống</param>
        /// <returns>URL hiển thị</returns>
        Task<string> GetUrlBySystemPath(string systemPath);
    }

    public class DocumentService : IDocumentService
    {
        private readonly MediaProcessingSettings _settings;
        private readonly IAppConfigService? _appConfigService;
        private readonly IRepository<Data.Domains.Medias.Media>? _mediaRepository;

        public DocumentService(IOptions<MediaProcessingSettings> settings, IAppConfigService? appConfigService = null, IRepository<Data.Domains.Medias.Media>? mediaRepository = null)
        {
            _settings = settings.Value;
            _appConfigService = appConfigService;
            _mediaRepository = mediaRepository;
        }

        public async Task<DocumentProcessResult> ProcessDocumentAsync(IFormFile file, DocumentType documentType, DocumentFormat documentFormat)
        {
            var result = new DocumentProcessResult
            {
                DocumentType = documentType
            };

            try
            {
                // 1. Validate tài liệu
                if (!await ValidateDocumentAsync(file, documentFormat))
                {
                    result.Result = Result.Failed;
                    result.Message = "File tải lên không phải là tài liệu hợp lệ hoặc không đúng định dạng";
                    return result;
                }

                // 2. Lưu file vào ổ đĩa
                var folderPath = GetDocumentFolderPath(documentType);
                var fileName = GenerateFileName(file);
                var savedFilePath = await SaveToDiskAsync(file, fileName, folderPath);

                // 3. Lấy thông tin file
                var fileInfo = new FileInfo(savedFilePath);
                result.FileSize = fileInfo.Length;
                result.Format = Path.GetExtension(savedFilePath).TrimStart('.').ToUpper();

                // 4. Tạo URL
                var url = await GenerateDocumentUrl(savedFilePath);
                result.Url = url;
                result.SystemPath = savedFilePath;
                result.Result = Result.Success;
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi xử lý tài liệu: {ex.Message}";
            }

            return result;
        }

        public async Task<DocumentProcessResult> ProcessAndSaveAsync(IFormFile file, DocumentSaveOptions options)
        {
            var result = await ProcessDocumentAsync(file, options.DocumentType, options.DocumentFormat);

            if (result.Result == Result.Success && options.SaveToDatabase && _mediaRepository != null)
            {
                try
                {
                    // Tạo metadata để lưu vào database
                    var mediaEntity = CreateMediaEntity(result, options);
                    var insertResult = await _mediaRepository.InsertAsync(mediaEntity);

                    if (insertResult > 0)
                    {
                        result.MediaId = mediaEntity.Id;
                    }
                    else
                    {
                        result.Message += " | Không thể lưu vào database";
                    }
                }
                catch (Exception ex)
                {
                    result.Message += $" | Lỗi lưu database: {ex.Message}";
                }
            }

            return result;
        }

        public async Task<bool> ValidateDocumentAsync(IFormFile file, DocumentFormat expectedFormat)
        {
            if (file == null || file.Length == 0)
                return false;

            try
            {
                using var stream = file.OpenReadStream();
                var headerBytes = new byte[8]; // Read more bytes for better validation
                await stream.ReadAsync(headerBytes, 0, 8);

                return ValidateDocumentHeader(headerBytes, file.FileName, expectedFormat);
            }
            catch
            {
                return false;
            }
        }

        public async Task<string> GetUrlBySystemPath(string systemPath)
        {
            try
            {
                string domain;
                string rootPath;

                if (_appConfigService != null)
                {
                    domain = await _appConfigService.GetConfigValueAsync("Media.Domain") ?? _settings.Domain;
                    rootPath = await _appConfigService.GetConfigValueAsync("Media.RootPath") ?? _settings.RootPath ?? throw new InvalidOperationException("RootPath not configured");
                }
                else
                {
                    domain = _settings.Domain;
                    rootPath = _settings.RootPath ?? throw new InvalidOperationException("RootPath not configured");
                }

                if (!string.IsNullOrEmpty(domain) && !string.IsNullOrEmpty(rootPath))
                {
                    // Normalize paths để đảm bảo consistent format
                    var normalizedSystemPath = systemPath.Replace("\\", "/");
                    var normalizedRootPath = rootPath.Replace("\\", "/").TrimEnd('/');

                    // Tạo relative path
                    var relativePath = normalizedSystemPath.Replace(normalizedRootPath + "/", "");

                    // Tạo URL
                    return $"{domain.TrimEnd('/')}/{relativePath}";
                }
            }
            catch (Exception)
            {
                // Log error if needed
            }

            return string.Empty;
        }

        #region Private Methods

        private string GetDocumentFolderPath(DocumentType documentType)
        {
            var now = DateTimeOffset.Now;
            var documentTypeName = Enum.GetName(documentType) ?? "General";
            return $"Documents\\{documentTypeName}\\{now.Year}\\{now.Month}\\{now.Day}\\";
        }

        private string GenerateFileName(IFormFile file)
        {
            var fileNameWithoutExt = Path.GetFileNameWithoutExtension(file.FileName);
            var fileExt = Path.GetExtension(file.FileName).ToLower();
            var fileName = fileNameWithoutExt.Length <= 90 ? fileNameWithoutExt : fileNameWithoutExt.Substring(0, 90);
            return $"{fileName}-{DateTimeOffset.Now.Ticks}{fileExt}";
        }

        private async Task<string> SaveToDiskAsync(IFormFile file, string fileName, string relativeFolder)
        {
            // Lấy RootPath từ AppConfigService (cached) hoặc fallback về settings
            var rootPath = _appConfigService != null
                ? await _appConfigService.GetConfigValueAsync("Media.RootPath") ?? _settings.RootPath ?? throw new InvalidOperationException("RootPath not configured")
                : _settings.RootPath ?? throw new InvalidOperationException("RootPath not configured");

            var fullFolderPath = Path.Combine(rootPath, relativeFolder);
            var filePath = Path.Combine(fullFolderPath, fileName);

            if (!Directory.Exists(fullFolderPath))
            {
                Directory.CreateDirectory(fullFolderPath);
            }

            var fileInfo = new FileInfo(filePath);
            if (fileInfo.Exists)
            {
                fileInfo.Delete();
            }

            using var fileStream = new FileStream(filePath, FileMode.Create);
            await file.CopyToAsync(fileStream);

            return filePath;
        }

        private Task<string> GenerateDocumentUrl(string systemPath)
        {
            return GetUrlBySystemPath(systemPath);
        }

        private bool ValidateDocumentHeader(byte[] headerBytes, string fileName, DocumentFormat expectedFormat)
        {
            var fileExt = Path.GetExtension(fileName).TrimStart('.').ToUpper();

            // Validate based on expected format
            switch (expectedFormat)
            {
                case DocumentFormat.PDF:
                    return ValidatePDF(headerBytes, fileExt);
                case DocumentFormat.Excel:
                    return ValidateExcel(headerBytes, fileExt);
                case DocumentFormat.Word:
                    return ValidateWord(headerBytes, fileExt);
                default:
                    return false;
            }
        }

        private bool ValidatePDF(byte[] headerBytes, string fileExt)
        {
            // PDF header: %PDF (0x25 0x50 0x44 0x46)
            if (fileExt != "PDF")
                return false;

            var pdfHeader = new byte[] { 0x25, 0x50, 0x44, 0x46 };
            return CompareArrays(pdfHeader, headerBytes.Take(4).ToArray());
        }

        private bool ValidateExcel(byte[] headerBytes, string fileExt)
        {
            // Excel files can be XLS or XLSX
            if (fileExt != "XLS" && fileExt != "XLSX")
                return false;

            // XLSX (ZIP-based): PK (0x50 0x4B)
            var xlsxHeader = new byte[] { 0x50, 0x4B };

            // XLS (OLE2): D0 CF 11 E0 A1 B1 1A E1
            var xlsHeader = new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };

            if (fileExt == "XLSX")
                return CompareArrays(xlsxHeader, headerBytes.Take(2).ToArray());
            else
                return CompareArrays(xlsHeader, headerBytes.Take(8).ToArray());
        }

        private bool ValidateWord(byte[] headerBytes, string fileExt)
        {
            // Word files can be DOC or DOCX
            if (fileExt != "DOC" && fileExt != "DOCX")
                return false;

            // DOCX (ZIP-based): PK (0x50 0x4B)
            var docxHeader = new byte[] { 0x50, 0x4B };

            // DOC (OLE2): D0 CF 11 E0 A1 B1 1A E1
            var docHeader = new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };

            if (fileExt == "DOCX")
                return CompareArrays(docxHeader, headerBytes.Take(2).ToArray());
            else
                return CompareArrays(docHeader, headerBytes.Take(8).ToArray());
        }

        private static bool CompareArrays(byte[] array1, byte[] array2)
        {
            if (array1.Length != array2.Length)
                return false;

            for (int i = 0; i < array1.Length; i++)
            {
                if (array1[i] != array2[i])
                    return false;
            }

            return true;
        }

        private Data.Domains.Medias.Media CreateMediaEntity(DocumentProcessResult result, DocumentSaveOptions options)
        {
            var currentTime = DateTimeHelper.CurrentTime();
            return new Data.Domains.Medias.Media
            {
                Id = Guid.NewGuid(),
                SystemPath = result.SystemPath,
                AltText = options.AltText ?? "Document",
                Caption = options.Caption ?? "Document",
                DisplayOrder = options.DisplayOrder,
                CreatedTime = currentTime,
                UpdatedTime = currentTime,
                CreatedBy = options.CreatedBy,
                CreatedByUserName = options.CreatedByUserName,
                UpdatedBy = options.UpdatedBy,
                UpdatedByUserName = options.UpdatedByUserName,
                // Business entity linking
                OrderId = options.OrderId ?? 0,
                OrderTrackId = options.OrderTrackId ?? Guid.Empty,
                OrderPackageId = options.OrderPackageId ?? 0
            };
        }

        #endregion
    }
}
