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

namespace Lada.Framework.Infrastructures.Services
{
    public interface IVideoService
    {
        /// <summary>
        /// Xử lý và lưu video với tối ưu hóa, trả về URL
        /// </summary>
        /// <param name="file">File video cần xử lý</param>
        /// <param name="videoType">Loại video (để tổ chức thư mục)</param>
        /// <returns>Kết quả xử lý video với URL</returns>
        Task<VideoProcessResult> ProcessVideoAsync(IFormFile file, VideoType videoType);

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

        /// <summary>
        /// Xử lý nhiều video cùng lúc
        /// </summary>
        /// <param name="files">Danh sách file video</param>
        /// <param name="videoType">Loại video</param>
        /// <returns>Danh sách kết quả xử lý</returns>
        Task<List<VideoProcessResult>> ProcessMultipleAsync(List<IFormFile> files, VideoType videoType);

        /// <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);

        /// <summary>
        /// Validate video bằng format và duration validation
        /// </summary>
        /// <param name="file">File cần validate</param>
        /// <returns>True nếu là video hợp lệ</returns>
        Task<bool> ValidateVideoAsync(IFormFile file);

        /// <summary>
        /// Lấy thông tin video (duration, resolution, format)
        /// </summary>
        /// <param name="filePath">Đường dẫn file video</param>
        /// <returns>Thông tin video</returns>
        Task<VideoInfo> GetVideoInfoAsync(string filePath);
    }

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

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

        public async Task<VideoProcessResult> ProcessVideoAsync(IFormFile file, VideoType videoType)
        {
            var result = new VideoProcessResult();

            try
            {
                // 1. Validate video
                if (!await ValidateVideoAsync(file))
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "File tải lên không phải là video hợp lệ";
                    return result;
                }

                // 2. Lưu file gốc tạm thời
                var originalFolderPath = GetVideoFolderPath(videoType);
                var originalFileName = GenerateFileName(file);
                var savedOriginalFilePath = await SaveToDiskAsync(file, originalFileName, originalFolderPath);

                // 3. Lấy thông tin video gốc
                var originalVideoInfo = await GetVideoInfoAsync(savedOriginalFilePath);

                // 4. Validate duration
                if (originalVideoInfo.Duration > _settings.MaxVideoDuration)
                {
                    RemoveFile(savedOriginalFilePath);
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = $"Video quá dài. Tối đa {_settings.MaxVideoDuration} giây";
                    return result;
                }

                // 5. Xử lý và tối ưu video
                var optimizedFilePath = await OptimizeVideoAsync(savedOriginalFilePath);

                // 6. Lấy thông tin video sau khi xử lý
                var optimizedVideoInfo = await GetVideoInfoAsync(optimizedFilePath);
                var fileInfo = new FileInfo(optimizedFilePath);

                result.FileSize = fileInfo.Length;
                result.Duration = optimizedVideoInfo.Duration;
                result.Width = optimizedVideoInfo.Width;
                result.Height = optimizedVideoInfo.Height;
                result.Format = Path.GetExtension(optimizedFilePath).TrimStart('.').ToUpper();

                // 7. Tạo URL
                var url = await GenerateVideoUrl(optimizedFilePath);
                result.Url = url;
                result.SystemPath = optimizedFilePath;
                result.Result = Lada.Framework.DTO.Result.Success;

                // 8. Xóa file gốc để tối ưu storage
                RemoveFile(savedOriginalFilePath);
            }
            catch (Exception ex)
            {
                result.Result = Lada.Framework.DTO.Result.SystemError;
                result.Message = $"Lỗi xử lý video: {ex.Message}";
            }

            return result;
        }

        public async Task<VideoProcessResult> ProcessAndSaveAsync(IFormFile file, VideoSaveOptions options)
        {
            var result = await ProcessVideoAsync(file, options.VideoType);

            if (result.Result == Lada.Framework.DTO.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);

                    // InsertAsync trả về số lượng records inserted, không phải ID
                    // ID được tự động generate và set vào entity sau khi insert
                    if (insertResult > 0)
                    {
                        result.MediaId = mediaEntity.Id; // Lấy ID từ entity sau khi insert
                    }
                    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<List<VideoProcessResult>> ProcessMultipleAsync(List<IFormFile> files, VideoType videoType)
        {
            var results = new List<VideoProcessResult>();

            if (files != null && files.Any())
            {
                foreach (var file in files)
                {
                    var result = await ProcessVideoAsync(file, videoType);
                    results.Add(result);
                }
            }

            return results;
        }

        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;
        }

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

            try
            {
                // Kiểm tra extension
                var allowedExtensions = new[] { ".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".webm" };
                var fileExtension = Path.GetExtension(file.FileName).ToLower();

                if (!allowedExtensions.Contains(fileExtension))
                    return false;

                // Kiểm tra MIME type
                var allowedMimeTypes = new[]
                {
                    "video/mp4", "video/avi", "video/x-msvideo", "video/quicktime",
                    "video/x-ms-wmv", "video/x-flv", "video/webm", "video/x-matroska"
                };

                if (!allowedMimeTypes.Contains(file.ContentType.ToLower()))
                    return false;

                return true;
            }
            catch
            {
                return false;
            }
        }

        public async Task<VideoInfo> GetVideoInfoAsync(string filePath)
        {
            var videoInfo = new VideoInfo();

            try
            {
                var ffmpegPath = GetFFmpegPath();
                var arguments = $"-i \"{filePath}\" -hide_banner";

                var processInfo = new ProcessStartInfo
                {
                    FileName = ffmpegPath,
                    Arguments = arguments,
                    RedirectStandardError = true,
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

                using var process = Process.Start(processInfo);
                if (process != null)
                {
                    var output = await process.StandardError.ReadToEndAsync();
                    await process.WaitForExitAsync();

                    // Parse FFmpeg output để lấy thông tin video
                    ParseVideoInfo(output, videoInfo);
                }
            }
            catch (Exception ex)
            {
                videoInfo.Error = ex.Message;
            }

            return videoInfo;
        }

        #region Private Methods

        private string GetVideoFolderPath(VideoType videoType)
        {
            var now = DateTimeOffset.Now;
            var videoTypeName = Enum.GetName(videoType) ?? "General";
            return $"Videos\\{videoTypeName}\\{now.Year}\\{now.Month}\\{now.Day}\\";
        }

        private string GenerateFileName(IFormFile file)
        {
            var fileNameWithoutExt = Path.GetFileNameWithoutExtension(file.FileName);
            var fileName = fileNameWithoutExt.Length <= 90 ? fileNameWithoutExt : fileNameWithoutExt.Substring(0, 90);
            return $"{fileName}-{DateTimeOffset.Now.Ticks}.mp4"; // Luôn output MP4
        }

        private async Task<string> SaveToDiskAsync(IFormFile file, string fileName, string relativeFolder)
        {
            // Lấy RootPath từ AppConfigService (cached) hoặc fallback về settings
            var rootPath = await _appConfigService.GetConfigValueAsync("Media.RootPath") ?? _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 async Task<string> OptimizeVideoAsync(string originalFilePath)
        {
            var fileInfo = new FileInfo(originalFilePath);
            var outputFolder = Path.Combine(fileInfo.Directory!.FullName, _settings.OutputFolder);
            var fileName = Path.GetFileNameWithoutExtension(originalFilePath);

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

            var outputFilePath = Path.Combine(outputFolder, $"{fileName}.mp4");

            var outputFileInfo = new FileInfo(outputFilePath);
            if (outputFileInfo.Exists)
            {
                outputFileInfo.Delete();
            }

            var ffmpegPath = GetFFmpegPath();
            var resolution = GetVideoResolution();

            // FFmpeg command để convert và optimize video
            var arguments = $"-i \"{originalFilePath}\" -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k -vf scale={resolution} -movflags +faststart \"{outputFilePath}\"";

            var processInfo = new ProcessStartInfo
            {
                FileName = ffmpegPath,
                Arguments = arguments,
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };

            using var process = Process.Start(processInfo);
            if (process != null)
            {
                await process.WaitForExitAsync();

                if (process.ExitCode != 0)
                {
                    var error = await process.StandardError.ReadToEndAsync();
                    throw new Exception($"FFmpeg error: {error}");
                }
            }

            return outputFilePath;
        }

        private string GetFFmpegPath()
        {
            if (!string.IsNullOrEmpty(_settings.FFmpegPath) && File.Exists(_settings.FFmpegPath))
            {
                return _settings.FFmpegPath;
            }

            // Thử tìm FFmpeg trong PATH
            return "ffmpeg";
        }

        private string GetVideoResolution()
        {
            return _settings.DefaultVideoResolution switch
            {
                VideoResolution.HD720 => "1280:720",
                VideoResolution.HD1080 => "1920:1080",
                VideoResolution.HD1440 => "2560:1440",
                VideoResolution.UHD4K => "3840:2160",
                _ => "1920:1080"
            };
        }

        private async Task<string> GenerateVideoUrl(string systemPath)
        {
            return await GetUrlBySystemPath(systemPath);
        }

        private void RemoveFile(string filePath)
        {
            try
            {
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
            }
            catch (Exception)
            {
                // Log error if needed, but don't fail the process
            }
        }

        private void ParseVideoInfo(string ffmpegOutput, VideoInfo videoInfo)
        {
            try
            {
                var lines = ffmpegOutput.Split('\n');

                foreach (var line in lines)
                {
                    // Parse duration: Duration: 00:01:30.45
                    if (line.Contains("Duration:"))
                    {
                        var durationMatch = System.Text.RegularExpressions.Regex.Match(line, @"Duration: (\d{2}):(\d{2}):(\d{2})\.(\d{2})");
                        if (durationMatch.Success)
                        {
                            var hours = int.Parse(durationMatch.Groups[1].Value);
                            var minutes = int.Parse(durationMatch.Groups[2].Value);
                            var seconds = int.Parse(durationMatch.Groups[3].Value);
                            videoInfo.Duration = hours * 3600 + minutes * 60 + seconds;
                        }
                    }

                    // Parse resolution: Stream #0:0: Video: h264, yuv420p, 1920x1080
                    if (line.Contains("Video:") && line.Contains("x"))
                    {
                        var resolutionMatch = System.Text.RegularExpressions.Regex.Match(line, @"(\d{3,4})x(\d{3,4})");
                        if (resolutionMatch.Success)
                        {
                            videoInfo.Width = int.Parse(resolutionMatch.Groups[1].Value);
                            videoInfo.Height = int.Parse(resolutionMatch.Groups[2].Value);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                videoInfo.Error = $"Parse error: {ex.Message}";
            }
        }

        private Lada.Framework.Data.Domains.Medias.Media CreateMediaEntity(VideoProcessResult result, VideoSaveOptions options)
        {
            return new Lada.Framework.Data.Domains.Medias.Media
            {
                Id = Guid.NewGuid(), // Tạo ID mới cho entity
                SystemPath = result.SystemPath,
                AltText = options.AltText ?? "Video",
                Caption = options.Caption ?? "Video",
                DisplayOrder = options.DisplayOrder,

                // Business entity linking (chỉ những properties có trong Media entity)
                OrderId = options.OrderId ?? 0,
                OrderTrackId = options.OrderTrackId ?? Guid.Empty,
                OrderPackageId = options.OrderPackageId ?? 0
            };
        }

        #endregion
    }
}
