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

namespace MBN_STOCK_WEBVIEW;

public sealed partial class MainWindow
{
    private readonly INativeOperatorLogWriter _nativeOperatorLogWriter =
        new NativeOperatorLogWriter();
    private readonly NativeOperatorLogTransitionTracker _nativeOperatorTransitionTracker =
        new();
    private readonly NativeOperatorCommandLogTracker _nativeOperatorCommandTracker =
        new();
    private int _nativeStartupRecorded;
    private int _nativeShutdownRecorded;

    private void LogNativeOperatorStartup()
    {
        if (Interlocked.Exchange(ref _nativeStartupRecorded, 1) == 0)
        {
            TryWriteNativeOperatorRecord(NativeOperatorLogRecord.ForStartup());
        }
    }

    private void LogNativeOperatorShutdown()
    {
        if (Interlocked.Exchange(ref _nativeShutdownRecorded, 1) == 0)
        {
            TryWriteNativeOperatorRecord(NativeOperatorLogRecord.ForShutdown());
        }
    }

    private void ObserveNativeDatabaseState(
        DataSourceKind source,
        DatabaseHealthState state)
    {
        if (_nativeOperatorTransitionTracker.TryObserveDatabaseState(
                source,
                state,
                out var record))
        {
            TryWriteNativeOperatorRecord(record);
        }
    }

    private void ObserveNativeTornadoState(PlayoutConnectionState state)
    {
        if (_nativeOperatorTransitionTracker.TryObserveTornadoState(state, out var record))
        {
            TryWriteNativeOperatorRecord(record);
        }
    }

    private void LogNativePlayoutCommandRequested(string command)
    {
        if (TryMapNativePlayoutCommand(command, out var mapped) &&
            _nativeOperatorCommandTracker.TryBegin(mapped, out var record))
        {
            TryWriteNativeOperatorRecord(record);
        }
    }

    private void LogNativePlayoutCommandCompleted(
        string command,
        PlayoutResultCode result)
    {
        if (!TryMapNativePlayoutCommand(command, out var mapped))
        {
            return;
        }

        if (result is PlayoutResultCode.OutcomeUnknown or PlayoutResultCode.TimedOut ||
            !TryMapNativePlayoutCompletion(result, out var completion))
        {
            if (_nativeOperatorCommandTracker.TryMarkOutcomeUnknown(mapped, out var unknownRecord))
            {
                TryWriteNativeOperatorRecord(unknownRecord);
            }
            return;
        }

        if (_nativeOperatorCommandTracker.TryComplete(mapped, completion, out var record))
        {
            TryWriteNativeOperatorRecord(record);
        }
    }

    private void LogNativePlayoutCommandCompleted(
        string command,
        NativeOperatorPlayoutCompletion completion)
    {
        if (TryMapNativePlayoutCommand(command, out var mapped) &&
            _nativeOperatorCommandTracker.TryComplete(mapped, completion, out var record))
        {
            TryWriteNativeOperatorRecord(record);
        }
    }

    private void LogNativePlayoutOutcomeUnknown(string command)
    {
        if (TryMapNativePlayoutCommand(command, out var mapped) &&
            _nativeOperatorCommandTracker.TryMarkOutcomeUnknown(mapped, out var record))
        {
            TryWriteNativeOperatorRecord(record);
        }
    }

    private void LogCurrentNativePlayoutOutcomeUnknown()
    {
        if (_nativeOperatorCommandTracker.TryMarkCurrentOutcomeUnknown(out var record))
        {
            TryWriteNativeOperatorRecord(record);
        }
    }

    private void TryWriteNativeOperatorRecord(NativeOperatorLogRecord record)
    {
        try
        {
            _ = _nativeOperatorLogWriter.TryWrite(record);
        }
        catch
        {
            // Logging is strictly best effort and cannot affect operator commands.
        }
    }

    private static bool TryMapNativePlayoutCommand(
        string command,
        out NativeOperatorPlayoutCommand mapped)
    {
        mapped = command switch
        {
            "prepare" => NativeOperatorPlayoutCommand.Prepare,
            "take-in" => NativeOperatorPlayoutCommand.TakeIn,
            "next" => NativeOperatorPlayoutCommand.Next,
            "take-out" => NativeOperatorPlayoutCommand.TakeOut,
            _ => default
        };
        return mapped != default;
    }

    private static bool TryMapNativePlayoutCompletion(
        PlayoutResultCode result,
        out NativeOperatorPlayoutCompletion mapped)
    {
        mapped = result switch
        {
            PlayoutResultCode.Success => NativeOperatorPlayoutCompletion.Succeeded,
            PlayoutResultCode.Rejected => NativeOperatorPlayoutCompletion.Rejected,
            PlayoutResultCode.Cancelled => NativeOperatorPlayoutCompletion.Cancelled,
            PlayoutResultCode.Unavailable => NativeOperatorPlayoutCompletion.Unavailable,
            PlayoutResultCode.Failed => NativeOperatorPlayoutCompletion.Failed,
            _ => default
        };
        return mapped != default;
    }
}
