using System.Runtime.Versioning;
using Kompas.Mcp.Core.Threading;
using Kompas6Constants;
using KompasAPI7;

namespace Kompas.Mcp.Core.Validation;

/// <summary>
/// Валидация построения активной детали/сборки: какие операции в ошибке или требуют перестроения.
/// Читает <c>IFeature7.Valid</c> / <c>ObjectError</c> / <c>State</c> по дереву (<c>SubFeatures</c>).
/// </summary>
[SupportedOSPlatform("windows")]
public sealed class ValidationService
{
    private const int KsFsRebuild = 0x2; // ksFeatureStateEnum.ksFSRebuild — «требует перестроения»

    private readonly KompasSession _session;
    private readonly KompasDispatcher _dispatcher;

    public ValidationService(KompasSession session, KompasDispatcher dispatcher)
    {
        _session = session ?? throw new ArgumentNullException(nameof(session));
        _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
    }

    /// <summary>
    /// Проверить активную деталь/сборку: вернуть список операций, которые вырождены (Valid=false),
    /// имеют код ошибки (ObjectError≠0) или помечены «требует перестроения». Пустой список — построение чистое.
    /// </summary>
    public Task<IReadOnlyList<OperationError>> ValidatePartAsync(CancellationToken ct = default)
        => _dispatcher.InvokeAsync<IReadOnlyList<OperationError>>(() =>
        {
            if (_session.Application.ActiveDocument is not IKompasDocument3D doc3d)
                throw new InvalidOperationException("Активный документ не является 3D-документом.");
            if (doc3d.TopPart is not IFeature7 top)
                throw new InvalidOperationException("Не удалось получить TopPart как IFeature7.");

            var result = new List<OperationError>();
            CheckFeature(top, result);
            foreach (var f in EnumerateSubFeatures(top))
                CheckFeature(f, result);
            return result;
        }, ct);

    private static IEnumerable<IFeature7> EnumerateSubFeatures(IFeature7 root)
    {
        object? subs = null;
        try { subs = root.SubFeatures[ksTreeTypeEnum.ksOperTree, true, false]; }
        catch { yield break; }

        if (subs is object[] arr)
        {
            foreach (var o in arr) if (o is IFeature7 f) yield return f;
        }
        else if (subs is System.Collections.IEnumerable en)
        {
            foreach (var o in en) if (o is IFeature7 f) yield return f;
        }
    }

    private static void CheckFeature(IFeature7 f, List<OperationError> acc)
    {
        bool valid = true;
        int err = 0, state = 0;
        try { valid = f.Valid; } catch { /* ignore */ }
        try { err = f.ObjectError; } catch { /* ignore */ }
        try { state = f.State; } catch { /* ignore */ }

        bool needsRebuild = (state & KsFsRebuild) != 0;
        if (valid && Errors3d.IsOk(err) && !needsRebuild) return;

        string name; try { name = f.Name ?? string.Empty; } catch { name = string.Empty; }
        acc.Add(new OperationError
        {
            Name = name,
            ErrorCode = err,
            Description = Errors3d.Describe(err),
            Valid = valid,
            NeedsRebuild = needsRebuild,
        });
    }
}
