using Adaptation.Shared;
using Adaptation.Shared.Methods;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;

namespace Adaptation.FileHandlers.ConvertExcelToJson;

public class ProcessData : IProcessData
{

    private readonly List<object> _Details;

    List<object> Shared.Properties.IProcessData.Details => _Details;

    public ProcessData(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection, string sheetName)
    {
        fileInfoCollection.Clear();
        _Details = new List<object>();
        Parse(fileRead, logistics, fileInfoCollection, sheetName);
    }

    string IProcessData.GetCurrentReactor(IFileRead fileRead, Logistics logistics, Dictionary<string, string> reactors)
        => throw new Exception(string.Concat("See ", nameof(Parse)));

    Tuple<string, Test[], JsonElement[], List<FileInfo>> IProcessData.GetResults(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection)
        => new(logistics.Logistics1[0], Array.Empty<Test>(), Array.Empty<JsonElement>(), fileInfoCollection);

#nullable enable

    /// <summary>
    /// https://social.msdn.microsoft.com/Forums/en-US/2e030743-5d66-4e53-bbff-bb2eee0cbc9b/readingwriting-excel-without-excel?forum=Vsexpressvcs
    /// </summary>
    private static DataTable GetSheet(string file, string selectSql)
    {
        DataTable results = new();
#if Linux
            ()("Built on Linux!");
#elif OSX
            ()("Built on macOS!");
#elif Windows || !NETCORE
#pragma warning disable CA1416
        for (int i = 0; i < int.MaxValue; i++)
        {
            try
            {
                OleDbConnectionStringBuilder connectionStringBuilder = new()
                {
                    Provider = "Microsoft.ACE.OLEDB.12.0",
                    DataSource = file
                };
                connectionStringBuilder.Add("Extended Properties", "Excel 12.0 Xml;HDR=YES;IMEX=1;ReadOnly=1;");
                using OleDbConnection connection = new(connectionStringBuilder.ConnectionString);
                connection.Open();
                using (OleDbDataAdapter adapter = new(selectSql, connection))
                    adapter.Fill(results);
                connection.Close();
                break;
            }
            catch (Exception)
            {
                if (i > 3) //2019-12-28 - 001
                    throw;
                System.Threading.Thread.Sleep(1000);
            }
#pragma warning restore CA1416
        }
#else
            ()("Built in unknown!");
#endif
        return results;
    }

    public static string DataTableToJSON(DataTable table)
    {
        string name;
        string value;
        object @object;
        StringBuilder jsonString = new();
        if (table.Rows.Count > 0)
        {
            _ = jsonString.Append('[');
            for (int i = 0; i < table.Rows.Count; i++)
            {
                _ = jsonString.Append('{');
                for (int j = 0; j < table.Columns.Count; j++)
                {
                    @object = table.Rows[i][j];
                    if (@object is null)
                        value = string.Empty;
                    else
                        value = JsonSerializer.Serialize(@object.ToString());
                    if (value.Contains("\\n"))
                        value = value.Replace("\\n", "<br>");
                    if (value.Contains("\\t"))
                        value = value.Replace("\\t", "  ");
                    name = JsonSerializer.Serialize(table.Columns[j].ColumnName.ToString().Trim());
                    if (name.Contains("\\n"))
                        name = name.Replace("\\n", "<br>");
                    if (name.Contains("\\t"))
                        name = name.Replace("\\t", "  ");
                    _ = jsonString.Append(name).Append(':').Append(value);
                    if (j < table.Columns.Count - 1)
                        _ = jsonString.Append(',');
                }
                if (i == table.Rows.Count - 1)
                    _ = jsonString.Append('}');
                else
                    _ = jsonString.Append("},");
            }
            _ = jsonString.Append(']');
        }
        return jsonString.ToString();
    }

    private static List<FIBacklogMesa> Parse(IFileRead fileRead, JsonElement[] jsonElements)
    {
        string key;
        string json;
        FIBacklogMesa? fiBacklogMesa;
        JsonProperty[] jsonProperties;
        List<FIBacklogMesa> fiBacklogMesaCollection = new();
        foreach (JsonElement jsonElement in jsonElements)
        {
            if (jsonElement.ValueKind != JsonValueKind.Object)
                continue;
            jsonProperties = jsonElement.EnumerateObject().ToArray();
            if (jsonProperties.Length < 2)
                continue;
            key = jsonProperties[0].Value.ToString();
            if (string.IsNullOrEmpty(key))
                continue;
            json = jsonElement.ToString();
            if (!fileRead.IsEAFHosted)
                File.WriteAllText(".json", json);
            fiBacklogMesa = JsonSerializer.Deserialize<FIBacklogMesa>(json);
            if (fiBacklogMesa is null)
                throw new NullReferenceException();
            fiBacklogMesaCollection.Add(fiBacklogMesa);
        }
        return fiBacklogMesaCollection;
    }

    private void Parse(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection, string sheet)
    {
        if (fileRead is null)
            throw new NullReferenceException();
        if (fileInfoCollection is null)
            throw new NullReferenceException();
        string selectSql = string.Concat("SELECT * FROM [", sheet, "$]");
        DataTable dataTable = GetSheet(logistics.ReportFullPath, selectSql);
        if (dataTable.Rows.Count == 0)
            throw new Exception("No rows");
        string json = DataTableToJSON(dataTable);
        if (!fileRead.IsEAFHosted)
            File.WriteAllText(".json", json);
        JsonElement[]? jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
        if (jsonElements is null || jsonElements.Length == 0)
            throw new NullReferenceException();
        if (!fileRead.ReportFullPath.Contains("Backlog"))
            json = JsonSerializer.Serialize(jsonElements, new JsonSerializerOptions() { WriteIndented = true });
        else
        {
            List<FIBacklogMesa> fiBacklogMesaCollection = Parse(fileRead, jsonElements);
            json = JsonSerializer.Serialize(from l in fiBacklogMesaCollection orderby l.Req.Length, l.Req select l, new JsonSerializerOptions() { WriteIndented = true });
        }
        if (!fileRead.IsEAFHosted)
            File.WriteAllText(".json", json);
        _Details.Add(json);
    }

}