using MBN_STOCK_WEBVIEW.Core.Playout;
using MMoneyCoderSharp.Data;

namespace MBN_STOCK_WEBVIEW.Infrastructure.Diagnostics;

/// <summary>
/// Converts closed runtime states into closed audit records and suppresses identical
/// consecutive states independently for Oracle, MariaDB, and Tornado.
/// </summary>
public sealed class NativeOperatorLogTransitionTracker
{
    private readonly object _sync = new();
    private NativeOperatorDatabaseState? _oracleState;
    private NativeOperatorDatabaseState? _mariaDbState;
    private NativeOperatorTornadoState? _tornadoState;

    public bool TryObserveDatabaseState(
        DataSourceKind source,
        DatabaseHealthState state,
        out NativeOperatorLogRecord record)
    {
        record = default;
        if (!TryMapDatabaseState(state, out var mapped))
        {
            return false;
        }

        lock (_sync)
        {
            switch (source)
            {
                case DataSourceKind.Oracle when _oracleState != mapped:
                    _oracleState = mapped;
                    record = NativeOperatorLogRecord.ForOracleStateChanged(mapped);
                    return true;
                case DataSourceKind.MariaDb when _mariaDbState != mapped:
                    _mariaDbState = mapped;
                    record = NativeOperatorLogRecord.ForMariaDbStateChanged(mapped);
                    return true;
                default:
                    return false;
            }
        }
    }

    public bool TryObserveTornadoState(
        PlayoutConnectionState state,
        out NativeOperatorLogRecord record)
    {
        record = default;
        if (!TryMapTornadoState(state, out var mapped))
        {
            return false;
        }

        lock (_sync)
        {
            if (_tornadoState == mapped)
            {
                return false;
            }

            _tornadoState = mapped;
            record = NativeOperatorLogRecord.ForTornadoStateChanged(mapped);
            return true;
        }
    }

    internal static bool TryMapDatabaseState(
        DatabaseHealthState state,
        out NativeOperatorDatabaseState mapped)
    {
        mapped = state switch
        {
            DatabaseHealthState.NotConfigured => NativeOperatorDatabaseState.NotConfigured,
            DatabaseHealthState.Healthy => NativeOperatorDatabaseState.Healthy,
            DatabaseHealthState.Unhealthy => NativeOperatorDatabaseState.Unhealthy,
            DatabaseHealthState.TimedOut => NativeOperatorDatabaseState.TimedOut,
            _ => default
        };
        return mapped != default;
    }

    internal static bool TryMapTornadoState(
        PlayoutConnectionState state,
        out NativeOperatorTornadoState mapped)
    {
        mapped = state switch
        {
            PlayoutConnectionState.Disabled => NativeOperatorTornadoState.Disabled,
            PlayoutConnectionState.DryRunReady => NativeOperatorTornadoState.DryRunReady,
            PlayoutConnectionState.Disconnected => NativeOperatorTornadoState.Disconnected,
            PlayoutConnectionState.Connecting => NativeOperatorTornadoState.Connecting,
            PlayoutConnectionState.Connected => NativeOperatorTornadoState.Connected,
            PlayoutConnectionState.Reconnecting => NativeOperatorTornadoState.Reconnecting,
            PlayoutConnectionState.Disconnecting => NativeOperatorTornadoState.Disconnecting,
            PlayoutConnectionState.Faulted => NativeOperatorTornadoState.Faulted,
            PlayoutConnectionState.OutcomeUnknown => NativeOperatorTornadoState.OutcomeUnknown,
            PlayoutConnectionState.Disposed => NativeOperatorTornadoState.Disposed,
            _ => default
        };
        return mapped != default;
    }
}

/// <summary>
/// Tracks the single serialized operator command without retaining request IDs or cue data.
/// Exactly one terminal record can be emitted for each accepted command.
/// </summary>
public sealed class NativeOperatorCommandLogTracker
{
    private readonly object _sync = new();
    private NativeOperatorPlayoutCommand? _currentCommand;
    private bool _terminalRecorded;

    public bool TryBegin(
        NativeOperatorPlayoutCommand command,
        out NativeOperatorLogRecord record)
    {
        record = default;
        if (!Enum.IsDefined(command))
        {
            return false;
        }

        lock (_sync)
        {
            _currentCommand = command;
            _terminalRecorded = false;
            record = NativeOperatorLogRecord.ForPlayoutCommandRequested(command);
            return true;
        }
    }

    public bool TryComplete(
        NativeOperatorPlayoutCommand command,
        NativeOperatorPlayoutCompletion completion,
        out NativeOperatorLogRecord record)
    {
        record = default;
        if (!Enum.IsDefined(command) || !Enum.IsDefined(completion))
        {
            return false;
        }

        lock (_sync)
        {
            if (_currentCommand != command || _terminalRecorded)
            {
                return false;
            }

            _terminalRecorded = true;
            record = NativeOperatorLogRecord.ForPlayoutCommandCompleted(command, completion);
            return true;
        }
    }

    public bool TryMarkOutcomeUnknown(
        NativeOperatorPlayoutCommand command,
        out NativeOperatorLogRecord record)
    {
        record = default;
        if (!Enum.IsDefined(command))
        {
            return false;
        }

        lock (_sync)
        {
            return TryMarkOutcomeUnknownLocked(command, out record);
        }
    }

    public bool TryMarkCurrentOutcomeUnknown(out NativeOperatorLogRecord record)
    {
        lock (_sync)
        {
            if (_currentCommand is not { } command)
            {
                record = default;
                return false;
            }

            return TryMarkOutcomeUnknownLocked(command, out record);
        }
    }

    private bool TryMarkOutcomeUnknownLocked(
        NativeOperatorPlayoutCommand command,
        out NativeOperatorLogRecord record)
    {
        record = default;
        if (_currentCommand != command || _terminalRecorded)
        {
            return false;
        }

        _terminalRecorded = true;
        record = NativeOperatorLogRecord.ForOutcomeUnknown(command);
        return true;
    }
}
