using Lada.Framework.DTO;
using Lada.Framework.DTO.Results;
using Lada.Framework.Infrastructures.AppSettings;
using Lada.Framework.Infrastructures.Helpers;
using Microsoft.Extensions.Options;
using OfficeOpenXml;

namespace Lada.Framework.Infrastructures.Services
{
    /// <summary>
    /// Giao diện cho dịch vụ quản lý file Excel
    /// </summary>
    public interface IExcelFileService
    {
        /// <summary>
        /// Lưu file Excel vào hệ thống
        /// </summary>
        /// <param name="excelPackage">Excel package cần lưu</param>
        /// <param name="fileName">Tên file (không bao gồm extension)</param>
        /// <param name="folderType">Loại thư mục (ví dụ: "reconciliations", "transfer-payment-bills")</param>
        /// <param name="subFolder">Thư mục con (tùy chọn)</param>
        /// <returns>Kết quả lưu file</returns>
        Task<ExcelFileResult> SaveExcelFileAsync(ExcelPackage excelPackage, string fileName, string folderType, string? subFolder = null);

        /// <summary>
        /// Lưu file Excel từ byte array
        /// </summary>
        /// <param name="fileBytes">Dữ liệu file Excel</param>
        /// <param name="fileName">Tên file (không bao gồm extension)</param>
        /// <param name="folderType">Loại thư mục</param>
        /// <param name="subFolder">Thư mục con (tùy chọn)</param>
        /// <returns>Kết quả lưu file</returns>
        Task<ExcelFileResult> SaveExcelFileAsync(byte[] fileBytes, string fileName, string folderType, string? subFolder = null);

        /// <summary>
        /// Xóa file Excel
        /// </summary>
        /// <param name="filePath">Đường dẫn file</param>
        /// <returns>Kết quả xóa</returns>
        Task<BaseResult> DeleteExcelFileAsync(string filePath);

        /// <summary>
        /// Lấy URL từ đường dẫn hệ thống
        /// </summary>
        /// <param name="filePath">Đường dẫn file</param>
        /// <returns>URL truy cập</returns>
        string GetUrlFromPath(string filePath);

        /// <summary>
        /// Lấy danh sách file Excel trong thư mục
        /// </summary>
        /// <param name="folderType">Loại thư mục</param>
        /// <param name="subFolder">Thư mục con (tùy chọn)</param>
        /// <returns>Danh sách file</returns>
        Task<List<ExcelFileInfo>> GetExcelFilesAsync(string folderType, string? subFolder = null);

        /// <summary>
        /// Tạo tên file unique
        /// </summary>
        /// <param name="baseFileName">Tên file cơ sở</param>
        /// <param name="includeTimestamp">Có bao gồm timestamp không</param>
        /// <returns>Tên file unique</returns>
        string GenerateUniqueFileName(string baseFileName, bool includeTimestamp = true);
    }

    /// <summary>
    /// Kết quả lưu file Excel
    /// </summary>
    public class ExcelFileResult : BaseResult
    {
        /// <summary>
        /// Tên file gốc
        /// </summary>
        public string? OriginalFileName { get; set; }

        /// <summary>
        /// Tên file đã lưu
        /// </summary>
        public string? SavedFileName { get; set; }

        /// <summary>
        /// Đường dẫn file đầy đủ
        /// </summary>
        public string? FilePath { get; set; }

        /// <summary>
        /// URL truy cập file
        /// </summary>
        public string? FileUrl { get; set; }

        /// <summary>
        /// Kích thước file (bytes)
        /// </summary>
        public long FileSize { get; set; }

        /// <summary>
        /// Thời gian lưu
        /// </summary>
        public DateTimeOffset SavedTime { get; set; }
    }

    /// <summary>
    /// Thông tin file Excel
    /// </summary>
    public class ExcelFileInfo
    {
        /// <summary>
        /// Tên file
        /// </summary>
        public string FileName { get; set; } = string.Empty;

        /// <summary>
        /// Đường dẫn file đầy đủ
        /// </summary>
        public string FilePath { get; set; } = string.Empty;

        /// <summary>
        /// URL truy cập
        /// </summary>
        public string FileUrl { get; set; } = string.Empty;

        /// <summary>
        /// Kích thước file (bytes)
        /// </summary>
        public long FileSize { get; set; }

        /// <summary>
        /// Thời gian tạo
        /// </summary>
        public DateTime CreatedTime { get; set; }

        /// <summary>
        /// Thời gian cập nhật
        /// </summary>
        public DateTime ModifiedTime { get; set; }
    }

    /// <summary>
    /// Triển khai dịch vụ quản lý file Excel
    /// </summary>
    public class ExcelFileService : IExcelFileService
    {
        private readonly MediaProcessingSettings _settings;
        private readonly IAppConfigService? _appConfigService;
        private readonly string[] _allowedExtensions = [".xlsx", ".xls"];
        private readonly long _maxFileSize = 50 * 1024 * 1024; // 50MB

        public ExcelFileService(IOptions<MediaProcessingSettings> settings, IAppConfigService? appConfigService = null)
        {
            _settings = settings.Value;
            _appConfigService = appConfigService;
        }

        /// <summary>
        /// Lưu file Excel từ ExcelPackage
        /// </summary>
        public async Task<ExcelFileResult> SaveExcelFileAsync(ExcelPackage excelPackage, string fileName, string folderType, string? subFolder = null)
        {
            var result = new ExcelFileResult();

            try
            {
                // Validate input
                if (excelPackage == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Excel package không được null";
                    return result;
                }

                if (string.IsNullOrEmpty(fileName))
                {
                    result.Result = Result.Failed;
                    result.Message = "Tên file không được để trống";
                    return result;
                }

                // Tạo tên file unique
                var uniqueFileName = GenerateUniqueFileName(fileName);
                var fullFileName = $"{uniqueFileName}.xlsx";

                // Tạo đường dẫn thư mục
                var folderPath = GetExcelFolderPath(folderType, subFolder);

                // Lưu file
                var savedFilePath = await SaveExcelPackageToDiskAsync(excelPackage, fullFileName, folderPath);

                // Tạo URL truy cập
                var fileUrl = await GetUrlBySystemPath(savedFilePath);

                // Lấy thông tin file
                var fileInfo = new FileInfo(savedFilePath);

                // Cập nhật kết quả
                result.Result = Result.Success;
                result.Message = "Lưu file Excel thành công";
                result.OriginalFileName = fileName;
                result.SavedFileName = fullFileName;
                result.FilePath = savedFilePath;
                result.FileUrl = fileUrl;
                result.FileSize = fileInfo.Length;
                result.SavedTime = DateTimeHelper.CurrentTime();
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi khi lưu file Excel: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Lưu file Excel từ byte array
        /// </summary>
        public async Task<ExcelFileResult> SaveExcelFileAsync(byte[] fileBytes, string fileName, string folderType, string? subFolder = null)
        {
            var result = new ExcelFileResult();

            try
            {
                // Validate input
                if (fileBytes == null || fileBytes.Length == 0)
                {
                    result.Result = Result.Failed;
                    result.Message = "Dữ liệu file không được null hoặc rỗng";
                    return result;
                }

                if (fileBytes.Length > _maxFileSize)
                {
                    result.Result = Result.Failed;
                    result.Message = $"File quá lớn. Kích thước tối đa cho phép là {_maxFileSize / (1024 * 1024)}MB";
                    return result;
                }

                if (string.IsNullOrEmpty(fileName))
                {
                    result.Result = Result.Failed;
                    result.Message = "Tên file không được để trống";
                    return result;
                }

                // Tạo tên file unique
                var uniqueFileName = GenerateUniqueFileName(fileName);
                var fullFileName = $"{uniqueFileName}.xlsx";

                // Tạo đường dẫn thư mục
                var folderPath = GetExcelFolderPath(folderType, subFolder);

                // Lưu file
                var savedFilePath = await SaveBytesToDiskAsync(fileBytes, fullFileName, folderPath);

                // Tạo URL truy cập
                var fileUrl = await GetUrlBySystemPath(savedFilePath);

                // Lấy thông tin file
                var fileInfo = new FileInfo(savedFilePath);

                // Cập nhật kết quả
                result.Result = Result.Success;
                result.Message = "Lưu file Excel thành công";
                result.OriginalFileName = fileName;
                result.SavedFileName = fullFileName;
                result.FilePath = savedFilePath;
                result.FileUrl = fileUrl;
                result.FileSize = fileInfo.Length;
                result.SavedTime = DateTimeHelper.CurrentTime();
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi khi lưu file Excel: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Xóa file Excel
        /// </summary>
        public Task<BaseResult> DeleteExcelFileAsync(string filePath)
        {
            var result = new BaseResult();

            try
            {
                if (string.IsNullOrEmpty(filePath))
                {
                    result.Result = Result.Success;
                    result.Message = "Không có file để xóa";
                    return Task.FromResult(result);
                }

                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }

                result.Result = Result.Success;
                result.Message = "Xóa file Excel thành công";
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi khi xóa file Excel: {ex.Message}";
            }

            return Task.FromResult(result);
        }

        /// <summary>
        /// Lấy URL từ đường dẫn hệ thống
        /// </summary>
        public string GetUrlFromPath(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
                return "";

            return GetUrlBySystemPath(filePath).Result;
        }

        /// <summary>
        /// Lấy danh sách file Excel trong thư mục
        /// </summary>
        public async Task<List<ExcelFileInfo>> GetExcelFilesAsync(string folderType, string? subFolder = null)
        {
            var files = new List<ExcelFileInfo>();

            try
            {
                var folderPath = GetExcelFolderPath(folderType, subFolder);

                if (Directory.Exists(folderPath))
                {
                    var excelFiles = Directory.GetFiles(folderPath, "*.xlsx")
                        .Concat(Directory.GetFiles(folderPath, "*.xls"))
                        .ToList();

                    foreach (var filePath in excelFiles)
                    {
                        var fileInfo = new FileInfo(filePath);
                        var fileUrl = await GetUrlBySystemPath(filePath);

                        files.Add(new ExcelFileInfo
                        {
                            FileName = fileInfo.Name,
                            FilePath = filePath,
                            FileUrl = fileUrl,
                            FileSize = fileInfo.Length,
                            CreatedTime = fileInfo.CreationTime,
                            ModifiedTime = fileInfo.LastWriteTime
                        });
                    }
                }
            }
            catch (Exception)
            {
                // Log error if needed
            }

            return files.OrderByDescending(f => f.ModifiedTime).ToList();
        }

        /// <summary>
        /// Tạo tên file unique
        /// </summary>
        public string GenerateUniqueFileName(string baseFileName, bool includeTimestamp = true)
        {
            if (string.IsNullOrEmpty(baseFileName))
                baseFileName = "ExcelFile";

            // Loại bỏ ký tự không hợp lệ
            var invalidChars = Path.GetInvalidFileNameChars();
            var cleanFileName = string.Join("_", baseFileName.Split(invalidChars, StringSplitOptions.RemoveEmptyEntries));

            // Giới hạn độ dài
            if (cleanFileName.Length > 100)
            {
                cleanFileName = cleanFileName.Substring(0, 100);
            }

            if (includeTimestamp)
            {
                var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
                return $"{cleanFileName}_{timestamp}";
            }

            return cleanFileName;
        }

        #region Private Methods

        /// <summary>
        /// Tạo đường dẫn thư mục cho file Excel theo cấu trúc Documents\Excel\{FolderType}\yyyy\mm\dd\
        /// </summary>
        private string GetExcelFolderPath(string folderType, string? subFolder = null)
        {
            var now = DateTimeOffset.Now;
            var basePath = $"Documents\\Excel\\{folderType}\\{now.Year}\\{now.Month}\\{now.Day}\\";

            if (!string.IsNullOrEmpty(subFolder))
            {
                basePath = Path.Combine(basePath, subFolder);
            }

            return basePath;
        }

        /// <summary>
        /// Lưu ExcelPackage vào đĩa
        /// </summary>
        private async Task<string> SaveExcelPackageToDiskAsync(ExcelPackage excelPackage, 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
                : _settings.RootPath;

            if (string.IsNullOrEmpty(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);
            }

            // Xóa file cũ nếu tồn tại
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            // Lưu ExcelPackage
            await excelPackage.SaveAsAsync(new FileInfo(filePath));

            return filePath;
        }

        /// <summary>
        /// Lưu byte array vào đĩa
        /// </summary>
        private async Task<string> SaveBytesToDiskAsync(byte[] fileBytes, 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
                : _settings.RootPath;

            if (string.IsNullOrEmpty(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);
            }

            // Xóa file cũ nếu tồn tại
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            // Lưu file
            await File.WriteAllBytesAsync(filePath, fileBytes);

            return filePath;
        }

        /// <summary>
        /// Tạo URL từ system path (tương tự CvUploadService)
        /// </summary>
        private 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;
        }

        #endregion
    }
}
