using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Threading.Tasks;
using NT8.Core.Common.Models;

namespace NT8.Core.MarketData
{
    /// <summary>
    /// Manages historical market data storage, retrieval, and archiving
    /// </summary>
    public class HistoricalDataManager
    {
        private readonly string _dataDirectory;
        private readonly bool _enableCompression;

        /// <summary>
        /// Constructor for HistoricalDataManager
        /// </summary>
        public HistoricalDataManager(string dataDirectory = null, bool enableCompression = true)
        {
            _dataDirectory = dataDirectory ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NT8", "MarketData");
            _enableCompression = enableCompression;

            // Ensure data directory exists
            if (!Directory.Exists(_dataDirectory))
            {
                Directory.CreateDirectory(_dataDirectory);
            }
        }

        /// <summary>
        /// Save historical bars to storage
        /// </summary>
        public async Task SaveHistoricalBars(string symbol, TimeSpan barSize, List<BarData> bars)
        {
            if (string.IsNullOrEmpty(symbol))
                throw new ArgumentException("Symbol cannot be null or empty", "symbol");

            if (bars == null)
                throw new ArgumentNullException("bars");

            var fileName = GenerateFileName(symbol, barSize, DateTime.UtcNow);
            var filePath = Path.Combine(_dataDirectory, fileName);

            // Convert bars to CSV format
            var csv = ConvertBarsToCsv(bars);

            if (_enableCompression)
            {
                await SaveCompressedFile(filePath + ".gz", csv);
            }
            else
            {
                await SaveTextFile(filePath + ".csv", csv);
            }
        }

        /// <summary>
        /// Load historical bars from storage
        /// </summary>
        public async Task<List<BarData>> LoadHistoricalBars(string symbol, TimeSpan barSize, DateTime date)
        {
            if (string.IsNullOrEmpty(symbol))
                throw new ArgumentException("Symbol cannot be null or empty", "symbol");

            var fileName = GenerateFileName(symbol, barSize, date);
            var filePath = Path.Combine(_dataDirectory, fileName);

            string csv;
            if (_enableCompression)
            {
                filePath += ".gz";
                if (!File.Exists(filePath))
                    return new List<BarData>();

                csv = await LoadCompressedFile(filePath);
            }
            else
            {
                filePath += ".csv";
                if (!File.Exists(filePath))
                    return new List<BarData>();

                csv = await LoadTextFile(filePath);
            }

            // Convert CSV back to BarData
            return ConvertCsvToBars(csv);
        }

        /// <summary>
        /// Archive old data files
        /// </summary>
        public async Task ArchiveOldData(DateTime olderThan)
        {
            var archiveDirectory = Path.Combine(_dataDirectory, "Archive");
            if (!Directory.Exists(archiveDirectory))
            {
                Directory.CreateDirectory(archiveDirectory);
            }

            var files = Directory.GetFiles(_dataDirectory, "*.csv*");
            foreach (var file in files)
            {
                var fileName = Path.GetFileName(file);
                var fileDate = ExtractDateFromFileName(fileName);

                if (fileDate < olderThan)
                {
                    var archivePath = Path.Combine(archiveDirectory, fileName);
                    await Task.Run(() => File.Move(file, archivePath));
                }
            }
        }

        /// <summary>
        /// Generate file name for data storage
        /// </summary>
        private string GenerateFileName(string symbol, TimeSpan barSize, DateTime date)
        {
            return string.Format("{0}_{1}_{2:yyyyMMdd}", symbol, (int)barSize.TotalMinutes, date);
        }

        /// <summary>
        /// Extract date from file name
        /// </summary>
        private DateTime ExtractDateFromFileName(string fileName)
        {
            // Extract date portion from file name
            var parts = fileName.Split('_');
            if (parts.Length >= 3)
            {
                var datePart = parts[2].Split('.')[0]; // Remove extension
                DateTime date;
                if (DateTime.TryParseExact(datePart, "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out date))
                {
                    return date;
                }
            }

            return DateTime.MinValue;
        }

        /// <summary>
        /// Convert bars to CSV format
        /// </summary>
        private string ConvertBarsToCsv(List<BarData> bars)
        {
            var sb = new StringBuilder();

            // Header
            sb.AppendLine("Symbol,Time,Open,High,Low,Close,Volume,BarSizeTicks");

            // Data rows
            foreach (var bar in bars)
            {
                sb.AppendFormat("{0},{1:yyyy-MM-dd HH:mm:ss},{2},{3},{4},{5},{6},{7}",
                    bar.Symbol,
                    bar.Time,
                    bar.Open,
                    bar.High,
                    bar.Low,
                    bar.Close,
                    bar.Volume,
                    bar.BarSize.Ticks);
                sb.AppendLine();
            }

            return sb.ToString();
        }

        /// <summary>
        /// Convert CSV to bars
        /// </summary>
        private List<BarData> ConvertCsvToBars(string csv)
        {
            var bars = new List<BarData>();
            var lines = csv.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

            // Skip header line
            for (int i = 1; i < lines.Length; i++)
            {
                var fields = lines[i].Split(',');
                if (fields.Length >= 8)
                {
                    try
                    {
                        var bar = new BarData(
                            fields[0], // Symbol
                            DateTime.Parse(fields[1]), // Time
                            double.Parse(fields[2]), // Open
                            double.Parse(fields[3]), // High
                            double.Parse(fields[4]), // Low
                            double.Parse(fields[5]), // Close
                            long.Parse(fields[6]), // Volume
                            TimeSpan.FromTicks(long.Parse(fields[7])) // BarSize
                        );

                        bars.Add(bar);
                    }
                    catch
                    {
                        // Skip invalid rows
                    }
                }
            }

            return bars;
        }

        /// <summary>
        /// Save compressed file
        /// </summary>
        private async Task SaveCompressedFile(string filePath, string content)
        {
            using (var fileStream = new FileStream(filePath, FileMode.Create))
            using (var gzipStream = new GZipStream(fileStream, CompressionMode.Compress))
            using (var writer = new StreamWriter(gzipStream))
            {
                await writer.WriteAsync(content);
            }
        }

        /// <summary>
        /// Load compressed file
        /// </summary>
        private async Task<string> LoadCompressedFile(string filePath)
        {
            using (var fileStream = new FileStream(filePath, FileMode.Open))
            using (var gzipStream = new GZipStream(fileStream, CompressionMode.Decompress))
            using (var reader = new StreamReader(gzipStream))
            {
                return await reader.ReadToEndAsync();
            }
        }

        /// <summary>
        /// Save text file
        /// </summary>
        private async Task SaveTextFile(string filePath, string content)
        {
            using (var writer = new StreamWriter(filePath))
            {
                await writer.WriteAsync(content);
            }
        }

        /// <summary>
        /// Load text file
        /// </summary>
        private async Task<string> LoadTextFile(string filePath)
        {
            using (var reader = new StreamReader(filePath))
            {
                return await reader.ReadToEndAsync();
            }
        }
    }
}
