using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Internals;
using Zorro; // For ZorroT6 and ZorroT6ArrayBuilder from your ZorroBinaryFiles.cs

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class BacktestYearlyDualExporterWithPrefix : Robot
    {
        [Parameter("Output Directory Path", DefaultValue = "C:\\Temp\\YearlyDualM1Export")]
        public string OutputDirectory { get; set; }

        [Parameter("Filename Prefix", DefaultValue = "cTrader")]
        public string FileNamePrefix { get; set; }

        private Dictionary<int, List<string>> _yearlyCsvData;
        private Dictionary<int, ZorroT6ArrayBuilder> _yearlyT6Builders;
        private string _symbolSpecificOutputPath; 

        protected override void OnStart()
        {
            _yearlyCsvData = new Dictionary<int, List<string>>();
            _yearlyT6Builders = new Dictionary<int, ZorroT6ArrayBuilder>();

            // Ensure Bars.Count is sufficient for .Last(1) access in OnBar, 
            // though OnBar typically isn't called until there are enough bars.
            if (Bars.Count < 2 && IsBacktesting) // Check specifically for backtesting context
            {
                Print("Warning: Not enough bars loaded at OnStart to determine initial data for .Last(1). Will proceed and rely on OnBar calls.");
            }


            try
            {
                Directory.CreateDirectory(OutputDirectory);
                _symbolSpecificOutputPath = Path.Combine(OutputDirectory, Symbol.Name);
                Directory.CreateDirectory(_symbolSpecificOutputPath);
            }
            catch (Exception ex)
            {
                Print($"Error creating output directories: {ex.Message}. Stopping cBot.");
                Stop();
                return;
            }
            
            Print($"cBot started. Data for symbol {Symbol.Name} ({TimeFrame}) during the backtest period will be collected.");
            Print($"Output will be saved to yearly files in: {_symbolSpecificOutputPath} with prefix '{FileNamePrefix}'");
        }

        protected override void OnBar()
        {
            // OnBar is called when a new bar opens.
            // We need data from the bar that just *closed*.
            // This corresponds to index [Bars.Count - 2] or .Last(1) on DataSeries.
            // Check if enough bars exist. In backtesting, OnBar implies at least 2 bars are loaded
            // (1 closed, 1 opening).
            if (Bars.Count < 2) 
            {
                // This should not happen in a normal OnBar sequence during backtesting
                // after the history has started loading.
                Print("Warning: OnBar called with Bars.Count < 2. Skipping this bar to prevent index error.");
                return;
            }
            
            // Correctly define barCloseTime as the OpenTime of the current, newly forming bar.
            // This is the actual closing moment of the previous bar.
            DateTime barCloseTime = Bars.OpenTimes.LastValue; // OpenTime of bar at index Bars.Count - 1
            
            // The year for file splitting should be based on the timestamp of the bar being recorded.
            // If barCloseTime represents the *end* of the period for lastBar, its year is appropriate.
            int currentBarYear = barCloseTime.Year; 

            // --- Ensure collections exist for the current year ---
            if (!_yearlyCsvData.ContainsKey(currentBarYear))
            {
                _yearlyCsvData[currentBarYear] = new List<string>();
                _yearlyCsvData[currentBarYear].Add("Timestamp,Open,High,Low,Close,Volume,Spread"); 
                
                _yearlyT6Builders[currentBarYear] = new ZorroT6ArrayBuilder();
                
                Print($"Started collecting data for year: {currentBarYear}. Filenames will use prefix '{FileNamePrefix}'.");
            }
            
            // --- Data points from the bar that just closed (using .Last(1) for each series) ---
            float open = (float)Bars.OpenPrices.Last(1);    // Data from bar at index Bars.Count - 2
            float high = (float)Bars.HighPrices.Last(1);    // Data from bar at index Bars.Count - 2
            float low = (float)Bars.LowPrices.Last(1);      // Data from bar at index Bars.Count - 2
            float close = (float)Bars.ClosePrices.Last(1);  // Data from bar at index Bars.Count - 2
            float tickVolume = (float)Bars.TickVolumes.Last(1); // Data from bar at index Bars.Count - 2
            float spreadPlaceholder = 0.0f;

            // --- Populate CSV Data for the current year ---
            string timestampStr = barCloseTime.ToString("yyyy-MM-dd HH:mm:ss");
            string openStr = open.ToString(CultureInfo.InvariantCulture);
            string highStr = high.ToString(CultureInfo.InvariantCulture);
            string lowStr = low.ToString(CultureInfo.InvariantCulture);
            string closeStr = close.ToString(CultureInfo.InvariantCulture);
            string volumeStrCsv = tickVolume.ToString(CultureInfo.InvariantCulture); 
            string spreadStrCsv = spreadPlaceholder.ToString("F1", CultureInfo.InvariantCulture); 

            _yearlyCsvData[currentBarYear].Add($"{timestampStr},{openStr},{highStr},{lowStr},{closeStr},{volumeStrCsv},{spreadStrCsv}");

            // --- Populate T6 Data for the current year ---
            _yearlyT6Builders[currentBarYear].Add(barCloseTime, high, low, open, close, spreadPlaceholder, tickVolume);
        }

        protected override void OnStop()
        {
            Print("Backtest finished. Saving collected data to yearly files...");

            // --- Save CSV data for each year ---
            foreach (var yearEntry in _yearlyCsvData)
            {
                int year = yearEntry.Key;
                List<string> csvLines = yearEntry.Value;
                string csvFileName = $"{FileNamePrefix}_{Symbol.Name}_{year}.csv";
                string csvFilePath = Path.Combine(_symbolSpecificOutputPath, csvFileName);

                if (csvLines.Count > 1) 
                {
                    Print($"Saving {csvLines.Count -1} data records to CSV: {csvFilePath}");
                    try
                    {
                        File.WriteAllLines(csvFilePath, csvLines, Encoding.UTF8);
                        Print($"Successfully saved CSV: {csvFilePath}");
                    }
                    catch (Exception ex)
                    {
                        Print($"Error writing CSV file '{csvFilePath}': {ex.Message}");
                    }
                }
                else
                {
                    Print($"No data (or only header) collected for CSV for year {year}. Skipping file: {csvFilePath}");
                }
            }

            // --- Save T6 binary data for each year ---
            foreach (var yearEntry in _yearlyT6Builders)
            {
                int year = yearEntry.Key;
                ZorroT6ArrayBuilder t6Builder = yearEntry.Value;
                string t6FileName = $"{FileNamePrefix}_{Symbol.Name}_{year}.t6";
                string t6FilePath = Path.Combine(_symbolSpecificOutputPath, t6FileName);

                if (t6Builder.Count > 0)
                {
                    Print($"Saving {t6Builder.Count} records to T6 binary: {t6FilePath}");
                    try
                    {
                        t6Builder.SaveToFile(t6FilePath);
                        Print($"Successfully saved T6: {t6FilePath}");
                    }
                    catch (Exception ex)
                    {
                        Print($"Error writing T6 binary file '{t6FilePath}': {ex.Message}");
                    }
                }
                else
                {
                     Print($"No data collected for T6 for year {year}. Skipping file: {t6FilePath}");
                }
            }

            Print("Yearly data export process completed.");
        }
    }
}