using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using NodePipeline.Abstractions.Models.Validation;

// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global

namespace NodePipeline.Abstractions;

public class PipelineRegistrationResult
{
    private readonly Dictionary<string, NodeValidationResult> _nodeValidationResults;
    private Dictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>? _errorParameters;
    private Dictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>? _errorPorts;
    private int? _errorsCount;
    private Dictionary<string, NodeValidationResult>? _invalidNodes;
    private Dictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>? _invalidParameters;
    private Dictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>? _invalidPorts;
    private Dictionary<string, NodeValidationResult>? _nodeErrors;
    private Dictionary<string, NodeValidationResult>? _nodeWarnings;
    private Dictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>? _warningParameters;
    private Dictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>? _warningPorts;
    private int? _warningsCount;

    public PipelineRegistrationResult(string pipelineId, bool isRegistered,
        Dictionary<string, NodeValidationResult> nodeValidationResults, bool treatWarningsAsErrors)
    {
        PipelineId = pipelineId;
        IsRegistered = isRegistered;
        _nodeValidationResults = nodeValidationResults
            .ToDictionary(x => x.Key, x => x.Value);
        TreatWarningsAsErrors = treatWarningsAsErrors;
    }


    public string PipelineId { get; }
    public bool IsRegistered { get; }

    public IReadOnlyDictionary<string, NodeValidationResult> NodeValidationResults =>
        new ReadOnlyDictionary<string, NodeValidationResult>(_nodeValidationResults);

    public bool TreatWarningsAsErrors { get; }

    public IReadOnlyDictionary<string, NodeValidationResult> NodeErrors
    {
        get
        {
            _nodeErrors ??= _nodeValidationResults
                .Where(q => q.Value.Result == ValidationResult.HasErrors)
                .ToDictionary(q => q.Key, q => q.Value);

            return new ReadOnlyDictionary<string, NodeValidationResult>(_nodeErrors);
        }
    }

    public IReadOnlyDictionary<string, NodeValidationResult> NodeWarnings
    {
        get
        {
            _nodeWarnings ??= _nodeValidationResults
                .Where(q => q.Value.Result == ValidationResult.HasWarnings)
                .ToDictionary(q => q.Key, q => q.Value);

            return new ReadOnlyDictionary<string, NodeValidationResult>(_nodeWarnings);
        }
    }

    public IReadOnlyDictionary<string, NodeValidationResult> InvalidNodes
    {
        get
        {
            _invalidNodes ??= _nodeValidationResults
                .Where(q => ValidationHelper.IsValid(q.Value.Result, TreatWarningsAsErrors))
                .ToDictionary(q => q.Key, q => q.Value);

            return new ReadOnlyDictionary<string, NodeValidationResult>(_invalidNodes);
        }
    }

    public IReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>> ErrorParameters
    {
        get
        {
            _errorParameters ??= NodeErrors
                .ToDictionary(q => q.Key,
                    IReadOnlyDictionary<string, List<NodeFieldValidationResult>> (q) =>
                        new ReadOnlyDictionary<string, List<NodeFieldValidationResult>>(q.Value.ParameterResults
                            .Where(x => x.Value.Any(z => z.Result == ValidationResult.HasErrors))
                            .ToDictionary(x => x.Key, x => x.Value)
                        ));

            return new ReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>(
                _errorParameters);
        }
    }

    public IReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>
        WarningParameters
    {
        get
        {
            _warningParameters ??= NodeValidationResults.Where(q => q.Value.Result != ValidationResult.Valid)
                .ToDictionary(q => q.Key,
                    IReadOnlyDictionary<string, List<NodeFieldValidationResult>> (q) =>
                        new ReadOnlyDictionary<string, List<NodeFieldValidationResult>>(q.Value.ParameterResults
                            .Where(x => x.Value.Any(z => z.Result == ValidationResult.HasWarnings))
                            .ToDictionary(x => x.Key, x => x.Value)
                        ));

            return new ReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>(
                _warningParameters);
        }
    }

    public IReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>
        InvalidParameters
    {
        get
        {
            _invalidParameters ??= InvalidNodes
                .ToDictionary(q => q.Key,
                    IReadOnlyDictionary<string, List<NodeFieldValidationResult>> (q) =>
                        new ReadOnlyDictionary<string, List<NodeFieldValidationResult>>(q.Value.ParameterResults
                            .Where(x => ValidationHelper.IsValid(x.Value.Select(z => z.Result),
                                TreatWarningsAsErrors))
                            .ToDictionary(x => x.Key, x => x.Value)
                        ));

            return new ReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>(
                _invalidParameters);
        }
    }

    public IReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>> ErrorPorts
    {
        get
        {
            _errorPorts ??= NodeErrors
                .ToDictionary(q => q.Key,
                    IReadOnlyDictionary<string, List<NodeFieldValidationResult>> (q) =>
                        new ReadOnlyDictionary<string, List<NodeFieldValidationResult>>(q.Value.PortResults
                            .Where(x => x.Value.Any(z => z.Result == ValidationResult.HasErrors))
                            .ToDictionary(x => x.Key, x => x.Value)
                        ));

            return new ReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>(
                _errorPorts);
        }
    }

    public IReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>> WarningPorts
    {
        get
        {
            _warningPorts ??= NodeValidationResults.Where(q => q.Value.Result != ValidationResult.Valid)
                .ToDictionary(q => q.Key,
                    IReadOnlyDictionary<string, List<NodeFieldValidationResult>> (q) =>
                        new ReadOnlyDictionary<string, List<NodeFieldValidationResult>>(q.Value.PortResults
                            .Where(x => x.Value.Any(z => z.Result == ValidationResult.HasWarnings))
                            .ToDictionary(x => x.Key, x => x.Value)
                        ));

            return new ReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>(
                _warningPorts);
        }
    }

    public IReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>> InvalidPorts
    {
        get
        {
            _invalidPorts ??= InvalidNodes
                .ToDictionary(q => q.Key,
                    IReadOnlyDictionary<string, List<NodeFieldValidationResult>> (q) =>
                        new ReadOnlyDictionary<string, List<NodeFieldValidationResult>>(q.Value.PortResults
                            .Where(x => ValidationHelper.IsValid(x.Value.Select(z => z.Result),
                                TreatWarningsAsErrors))
                            .ToDictionary(x => x.Key, x => x.Value)
                        ));

            return new ReadOnlyDictionary<string, IReadOnlyDictionary<string, List<NodeFieldValidationResult>>>(
                _invalidPorts);
        }
    }

    public int WarningsCount
    {
        get
        {
            _warningsCount ??= WarningParameters.Sum(q => q.Value.Count) +
                               WarningPorts.Sum(q => q.Value.Count);

            return _warningsCount.Value;
        }
    }

    public int ErrorsCount
    {
        get
        {
            _errorsCount ??= ErrorParameters.Sum(q => q.Value.Count) +
                             ErrorPorts.Sum(q => q.Value.Count);

            return _errorsCount.Value;
        }
    }

    public IReadOnlyDictionary<string, NodeValidationResult> GetNotValidNodes()
    {
        return new ReadOnlyDictionary<string, NodeValidationResult>(NodeValidationResults
            .Where(q => q.Value.Result != ValidationResult.Valid)
            .ToDictionary(kvp => kvp.Key, kvp => kvp.Value));
    }
}