using System.Text.Json;
using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;
using MBN_STOCK_WEBVIEW.Playout.Configuration;
using Microsoft.UI.Xaml;
using Windows.Storage.Pickers;
using WinRT.Interop;

namespace MBN_STOCK_WEBVIEW;

public sealed partial class MainWindow
{
    private int _backgroundSelectionInFlight;

    private void HandleBackgroundStatusRequest(JsonElement payload)
    {
        if (!TryParseBackgroundRequest(payload, out var requestId))
        {
            PostBackgroundError(string.Empty, "올바르지 않은 배경 상태 요청입니다.");
            return;
        }

        PostBackgroundStatus(requestId);
    }

    private async Task HandleChooseBackgroundAsync(JsonElement payload)
    {
        if (!TryParseBackgroundRequest(payload, out var requestId))
        {
            PostBackgroundError(string.Empty, "올바르지 않은 배경 파일 선택 요청입니다.");
            return;
        }

        if (!await _playoutCommandGate.WaitAsync(0))
        {
            PostBackgroundError(requestId, "송출 명령 처리 중에는 배경을 변경할 수 없습니다.");
            return;
        }

        string? error = null;
        var message = "배경 파일 선택을 취소했습니다.";
        Interlocked.Exchange(ref _backgroundSelectionInFlight, 1);
        try
        {
            if (!CanChangeLegacyBackground(allowBackgroundOperation: true))
            {
                error = "배경은 IDLE 상태에서 다음 PREPARE 전에만 변경할 수 있습니다.";
                return;
            }

            var source = _legacyCompositionOptionsSource ??
                throw new InvalidOperationException("Background composition is unavailable.");

            // Original btnback_Click assigns 배경\기본.vrv before opening the dialog.
            // Keep that behavior only when the default passes all trusted-file checks.
            try
            {
                source.Update(PlayoutSceneCompositionFactory.CreateLegacyDefault(
                    _playoutOptions!,
                    source.Current.FadeDuration));
            }
            catch (PlayoutConfigurationException)
            {
                // F2 may still select another valid file from the same trusted root.
            }

            var picker = new FileOpenPicker
            {
                SuggestedStartLocation = PickerLocationId.PicturesLibrary,
                ViewMode = PickerViewMode.List
            };
            picker.FileTypeFilter.Add(".vrv");
            picker.FileTypeFilter.Add(".jpg");
            picker.FileTypeFilter.Add(".jpeg");
            picker.FileTypeFilter.Add(".png");
            InitializeWithWindow.Initialize(picker, WindowNative.GetWindowHandle(this));

            var selected = await picker.PickSingleFileAsync();
            if (selected is null)
            {
                return;
            }

            if (!CanChangeLegacyBackground(allowBackgroundOperation: true))
            {
                error = "배경 파일 선택 중 송출 상태가 바뀌어 변경을 취소했습니다.";
                return;
            }

            var composition = CreateOperatorBackgroundComposition(selected.Path);
            source.Update(composition);
            message = "선택한 배경을 다음 PREPARE부터 사용합니다.";
        }
        catch (Exception exception) when (
            exception is ArgumentException or IOException or UnauthorizedAccessException or
                PlayoutConfigurationException)
        {
            error = "배경은 신뢰 배경 폴더 안의 일반 vrv/jpg/jpeg/png 파일만 선택할 수 있습니다.";
        }
        catch
        {
            error = "배경 파일을 선택하지 못했습니다.";
        }
        finally
        {
            Interlocked.Exchange(ref _backgroundSelectionInFlight, 0);
            _playoutCommandGate.Release();

            if (error is null)
            {
                PostBackgroundStatus(requestId, message);
            }
            else
            {
                PostBackgroundError(requestId, error);
            }
        }
    }

    private async Task HandleToggleBackgroundAsync(JsonElement payload)
    {
        if (!TryParseBackgroundRequest(payload, out var requestId))
        {
            PostBackgroundError(string.Empty, "올바르지 않은 배경 토글 요청입니다.");
            return;
        }

        if (!await _playoutCommandGate.WaitAsync(0))
        {
            PostBackgroundError(requestId, "송출 명령 처리 중에는 배경을 변경할 수 없습니다.");
            return;
        }

        string? error = null;
        var message = string.Empty;
        Interlocked.Exchange(ref _backgroundSelectionInFlight, 1);
        try
        {
            if (!CanChangeLegacyBackground(allowBackgroundOperation: true))
            {
                error = "배경은 IDLE 상태에서 다음 PREPARE 전에만 변경할 수 있습니다.";
                return;
            }

            var source = _legacyCompositionOptionsSource ??
                throw new InvalidOperationException("Background composition is unavailable.");
            var current = source.Current;
            if (current.BackgroundKind == LegacySceneBackgroundKind.None)
            {
                try
                {
                    source.Update(PlayoutSceneCompositionFactory.CreateLegacyDefault(
                        _playoutOptions!,
                        current.FadeDuration));
                    message = "기본 배경을 켰습니다. 다음 PREPARE부터 반영됩니다.";
                }
                catch (PlayoutConfigurationException)
                {
                    error = "신뢰 배경 폴더의 기본.vrv를 확인할 수 없습니다. F2로 유효한 배경을 선택하세요.";
                    return;
                }
            }
            else
            {
                source.Update(new LegacySceneCueCompositionOptions(
                    current.FadeDuration,
                    LegacySceneBackgroundKind.None));
                message = "배경 사용을 껐습니다. 다음 PREPARE부터 반영됩니다.";
            }
        }
        catch
        {
            error = "배경 사용 상태를 변경하지 못했습니다.";
        }
        finally
        {
            Interlocked.Exchange(ref _backgroundSelectionInFlight, 0);
            _playoutCommandGate.Release();

            if (error is null)
            {
                PostBackgroundStatus(requestId, message);
            }
            else
            {
                PostBackgroundError(requestId, error);
            }
        }
    }

    private LegacySceneCueCompositionOptions CreateOperatorBackgroundComposition(
        string selectedPath)
    {
        var options = _playoutOptions ??
            throw new InvalidOperationException("Playout options are unavailable.");
        var source = _legacyCompositionOptionsSource ??
            throw new InvalidOperationException("Background composition is unavailable.");
        return PlayoutSceneCompositionFactory.CreateOperatorSelection(
            options,
            source.Current.FadeDuration,
            selectedPath);
    }

    private bool CanChangeLegacyBackground(bool allowBackgroundOperation = false)
    {
        if (_playoutOptions is null || _legacyCompositionOptionsSource is null ||
            !PlayoutSceneCompositionFactory.TryGetTrustedBackgroundDirectory(
                _playoutOptions,
                out _) ||
            IsBrowserCorrelationQuarantined() ||
            (!allowBackgroundOperation &&
                Volatile.Read(ref _backgroundSelectionInFlight) != 0) ||
            Volatile.Read(ref _playoutCommandInFlight) != 0 ||
            Volatile.Read(ref _playoutShutdownStarted) != 0)
        {
            return false;
        }

        var status = _playoutEngine?.Status;
        var workflow = _playoutWorkflow?.State;
        return status is not null && workflow is not null &&
            !status.IsPlayCompletionPending &&
            string.IsNullOrWhiteSpace(status.PreparedSceneName) &&
            string.IsNullOrWhiteSpace(status.OnAirSceneName) &&
            string.IsNullOrWhiteSpace(workflow.PreparedCutCode) &&
            string.IsNullOrWhiteSpace(workflow.OnAirCutCode) &&
            (_legacyRefreshTask is null || _legacyRefreshTask.IsCompleted);
    }

    private static bool TryParseBackgroundRequest(JsonElement payload, out string requestId)
    {
        requestId = string.Empty;
        return payload.ValueKind == JsonValueKind.Object &&
            HasOnlyProperties(payload, "requestId") &&
            TryGetSafeToken(
                payload,
                "requestId",
                MaximumPlayoutRequestIdLength,
                out requestId);
    }

    private void PostBackgroundStatus(string requestId, string? message = null)
    {
        var current = _legacyCompositionOptionsSource?.Current ??
            LegacySceneCueCompositionOptions.Default;
        var enabled = current.BackgroundKind != LegacySceneBackgroundKind.None;
        var rootAvailable = _playoutOptions is not null &&
            PlayoutSceneCompositionFactory.TryGetTrustedBackgroundDirectory(
                _playoutOptions,
                out _);
        var defaultAvailable = false;
        if (rootAvailable && _playoutOptions is not null)
        {
            try
            {
                _ = PlayoutSceneCompositionFactory.CreateLegacyDefault(
                    _playoutOptions,
                    current.FadeDuration);
                defaultAvailable = true;
            }
            catch (PlayoutConfigurationException)
            {
                // F2 remains available for another valid file in the trusted root.
            }
        }

        PostMessage("background-status", new
        {
            requestId,
            enabled,
            kind = current.BackgroundKind switch
            {
                LegacySceneBackgroundKind.Texture => "texture",
                LegacySceneBackgroundKind.Video => "video",
                _ => "none"
            },
            fileName = enabled ? Path.GetFileName(current.BackgroundAssetPath) : string.Empty,
            canChange = CanChangeLegacyBackground(),
            message = message ?? (!rootAvailable
                ? "신뢰 배경 폴더를 찾을 수 없어 F2/F3 배경 기능을 잠갔습니다."
                : enabled
                    ? "선택한 배경은 다음 PREPARE부터 적용됩니다."
                    : defaultAvailable
                        ? "배경 사용 안 함"
                        : "기본.vrv가 없습니다. F2로 신뢰 배경 폴더의 파일을 선택하세요.")
        });
    }

    private void PostBackgroundError(string requestId, string message)
    {
        PostMessage("background-error", new
        {
            requestId,
            message
        });
    }
}
