using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Models.Stateless;
using System.Text.Json;

namespace OI.Metrology.Server.Repository;

public class PinRepository : IPinRepository
{

    private readonly string _MockRoot;
    private readonly Serilog.ILogger _Log;
    private readonly string _RepositoryName;
    private readonly Dictionary<string, Dictionary<long, HeaderCommon>> _RdsToHeaderCommonCollection;

    public PinRepository(string mockRoot)
    {
        _MockRoot = mockRoot;
        _RdsToHeaderCommonCollection = new();
        _RepositoryName = nameof(PinRepository)[..^10];
        _Log = Serilog.Log.ForContext<PinRepository>();
    }

    void IPinRepository.SetPinnedTable(HeaderCommon headerCommon)
    {
        Dictionary<long, HeaderCommon>? toolIdToHeader;
        if (!string.IsNullOrEmpty(headerCommon.RDS))
        {
            if (!_RdsToHeaderCommonCollection.TryGetValue(headerCommon.RDS, out toolIdToHeader))
            {
                _RdsToHeaderCommonCollection.Add(headerCommon.RDS, new());
                if (!_RdsToHeaderCommonCollection.TryGetValue(headerCommon.RDS, out toolIdToHeader))
                    throw new Exception();
            }
            if (toolIdToHeader.ContainsKey(headerCommon.ToolTypeID))
                toolIdToHeader[headerCommon.ToolTypeID] = headerCommon;
            else
                toolIdToHeader.Add(headerCommon.ToolTypeID, headerCommon);
        }
    }

    private (HeaderCommon?, HeaderCommon?) GetBoth(string rds, long bioRadId, long cdeId)
    {
        Dictionary<long, HeaderCommon>? toolIdToHeader;
        if (!_RdsToHeaderCommonCollection.TryGetValue(rds, out toolIdToHeader))
        {
            _RdsToHeaderCommonCollection.Add(rds, new());
            if (!_RdsToHeaderCommonCollection.TryGetValue(rds, out toolIdToHeader))
                throw new Exception();
        }
        _ = toolIdToHeader.TryGetValue(cdeId, out HeaderCommon? cdeHeader);
        _ = toolIdToHeader.TryGetValue(bioRadId, out HeaderCommon? bioRadHeader);
        return new(bioRadHeader, cdeHeader);
    }

    private static Pinned? GetPinned(IMetrologyRepository metrologyRepository, HeaderCommon headerCommon, int points, int column)
    {
        Pinned? result;
        List<string> values;
        System.Data.DataTable dataTable = metrologyRepository.GetData((int)headerCommon.ToolTypeID, headerCommon.ID);
        if (dataTable.Rows.Count <= points || dataTable.Columns.Count <= column)
            result = null;
        else
        {
            values = new();
            for (int i = 0; i < dataTable.Rows.Count - 1; i++)
            {
                if (dataTable.Rows[i]?.ItemArray[column] is null)
                    break;
                values.Add(string.Concat(dataTable.Rows[i].ItemArray[column]));
            }
            if (values.Count <= points)
                result = null;
            else
                result = new(headerCommon, values);
        }
        return result;
    }

    Result<Pinned[]> IPinRepository.GetPinnedTable(IMetrologyRepository metrologyRepository, int id, string? biorad_id, string? cde_id, string? rds)
    {
        Result<Pinned[]>? r;
        if (!string.IsNullOrEmpty(_MockRoot))
        {
            string json = File.ReadAllText(Path.Combine(string.Concat(AppContext.BaseDirectory, _MockRoot), $"{_RepositoryName}-{nameof(IPinRepository.GetPinnedTable)}.json"));
            r = JsonSerializer.Deserialize<Result<Pinned[]>>(json);
            if (r is null)
                throw new NullReferenceException(nameof(r));
        }
        else
        {
            if (string.IsNullOrEmpty(rds) || !long.TryParse(biorad_id, out long bioRadId) || !long.TryParse(cde_id, out long cdeId))
                r = new() { Results = Array.Empty<Pinned>(), TotalRows = 0 };
            else
            {
                const int points = 9;
                List<Pinned> results = new();
                (HeaderCommon? bioRadHeader, HeaderCommon? cdeHeader) = GetBoth(rds, bioRadId, cdeId);
                if (bioRadHeader is not null)
                {
                    const int thickness = 5;
                    Pinned? pinned = GetPinned(metrologyRepository, bioRadHeader, points, column: thickness);
                    if (pinned is not null)
                        results.Add(pinned);
                }
                if (cdeHeader is not null)
                {
                    const int rs = 6;
                    Pinned? pinned = GetPinned(metrologyRepository, cdeHeader, points, column: rs);
                    if (pinned is not null)
                        results.Add(pinned);
                }
                r = new()
                {
                    Results = results.ToArray(),
                    TotalRows = results.Count,
                };
            }
        }
        return r;
    }

}