using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Threading.Tasks;
using BattSim.Models;
using Microsoft.AspNetCore.Components.Forms;

namespace BattSim.Services
{
    public static class FluviusDataHandler
    {
        public static async Task<EnergyData[]> LoadAndProcessFile(IBrowserFile file)
        {
            var lines = await ReadCsvFile(file);
            var energyData = new ConcurrentDictionary<DateTime,EnergyData>(); // Thread-safe collection
            // Process lines in parallel
            Parallel.ForEach(lines, line =>
            {
                try
                {
                    var parts = SplitLine(line);
                    DateTime time = ParseDateTime(parts[..2]);
                    double volume = ParseVolume(parts[8]);
                    string register = parts[7].Trim();
                    bool dayTarif = register.Contains("Dag");

                    var entry = new EnergyData { Time = time, DayTariff = dayTarif };
                    if (register.Contains("Afname"))
                        entry.Consumption = volume;
                    else if (register.Contains("Injectie"))
                        entry.Production = volume;
                    else
                        throw new Exception("Unknown volume register");

                    energyData.AddOrUpdate(entry.Time, entry, (_, existing) =>
                    {
                        existing.Consumption += entry.Consumption;
                        existing.Production += entry.Production;
                        return existing;
                    });
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Error parsing line: {line}. Skipping to next line. Exception: {e}");
                }
            });
            var results = energyData.Values.ToArray();
            results.Sort((a,b)=>a.Time.CompareTo(b.Time));
            return results;
        }

        public static EnergyData[] GenerateDailyData(EnergyData[] energyData)
        {
            var dailyEnergyData = new ConcurrentDictionary<DateOnly, EnergyData>();
            Parallel.ForEach(energyData, energy =>
            {
                var date = DateOnly.FromDateTime(energy.Time);

                // Use AddOrUpdate to avoid double lookup
                dailyEnergyData.AddOrUpdate(
                    date,
                    new EnergyData(energy), // If key doesn't exist, add this value
                    (_, existing) =>
                    {
                        // If key exists, aggregate the values
                        existing.Consumption += energy.Consumption;
                        existing.Production += energy.Production;
                        return existing;
                    }
                );
            });
            return dailyEnergyData.Values.ToArray();
        }

        private static async Task<List<string>> ReadCsvFile(IBrowserFile file)
        {
            await using var stream = file.OpenReadStream(maxAllowedSize: (int)1.0e9);
            using var reader = new StreamReader(stream, bufferSize: (int)1.0e6);

            // Skip header
            await reader.ReadLineAsync();
            // Read all lines into memory
            var lines = new List<string>();
            string? line;
            while ((line = await reader.ReadLineAsync()) is not null)
            {
                lines.Add(line);
            }
            return lines;
        }

        private static string[] SplitLine(string line)
        {
            var parts = line.Split(';');
            if (parts.Length < 9)
                throw new Exception($"Malformed line (too many parts): {line}");
            return parts;
        }

        private static DateTime ParseDateTime(string[] dateTimeStrings)
        {
            string dateTimeString = dateTimeStrings[0] + " " + dateTimeStrings[1];
            return DateTime.ParseExact(dateTimeString, "dd-MM-yyyy HH:mm:ss", CultureInfo.GetCultureInfo("nl-BE"));
        }

        private static double ParseVolume(string volumeString)
        {
            var volumeStr = volumeString.Trim();
            return string.IsNullOrEmpty(volumeStr)
                ? 0
                : double.Parse(volumeStr.Replace(",", "."), CultureInfo.InvariantCulture);
        }
    }
}