using MBN_STOCK_WEBVIEW.Core.Playout;
using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;

namespace MBN_STOCK_WEBVIEW.Playout.Configuration;

/// <summary>
/// Validates the MainForm-level fade/background composition before the first DryRun
/// or actual PREPARE. Background paths stay native/trusted; fade is restricted to the
/// original closed DissolveTime selector index (0..19).
/// </summary>
public static class PlayoutSceneCompositionFactory
{
    public const string LegacyDefaultBackgroundFileName = "기본.vrv";
    public const string LegacyStartupDefaultBackgroundAssetPath = @"video\기본.vrv";

    private static readonly IReadOnlySet<string> AllowedExtensions = new HashSet<string>(
    [
        ".png", ".jpg", ".jpeg", ".bmp", ".tga", ".dds",
        ".vrv", ".avi", ".mp4", ".mov"
    ], StringComparer.OrdinalIgnoreCase);

    public static LegacySceneCueCompositionOptions Create(PlayoutOptions options)
    {
        ArgumentNullException.ThrowIfNull(options);
        ValidateCommon(options.LegacySceneFadeDuration, options);

        if (options.LegacySceneBackgroundKind == LegacySceneBackgroundKind.None)
        {
            if (!string.IsNullOrWhiteSpace(options.LegacySceneBackgroundAssetPath))
            {
                throw Invalid();
            }

            return new LegacySceneCueCompositionOptions(
                options.LegacySceneFadeDuration,
                LegacySceneBackgroundKind.None);
        }

        try
        {
            var root = RequireTrustedBackgroundDirectory(options);
            var candidate = TrustedPlayoutAssetPath.ResolveRelativeFile(
                root,
                options.LegacySceneBackgroundAssetPath ?? string.Empty,
                AllowedExtensions);
            return CreateResult(
                options,
                options.LegacySceneFadeDuration,
                options.LegacySceneBackgroundKind,
                Path.GetRelativePath(root, candidate));
        }
        catch (TrustedPlayoutAssetException)
        {
            throw Invalid();
        }
    }

    /// <summary>
    /// Validates one F2 picker result against the separate background root. An
    /// absolute path is accepted only at this native boundary and is converted back
    /// to a closed relative path before it reaches the scene builder.
    /// </summary>
    public static LegacySceneCueCompositionOptions CreateOperatorSelection(
        PlayoutOptions options,
        int fadeDuration,
        string selectedAbsolutePath)
    {
        ArgumentNullException.ThrowIfNull(options);
        ValidateCommon(fadeDuration, options);

        try
        {
            var root = RequireTrustedBackgroundDirectory(options);
            var candidate = TrustedPlayoutAssetPath.ResolveAbsoluteFile(
                root,
                selectedAbsolutePath,
                AllowedExtensions);
            var extension = Path.GetExtension(candidate);
            var kind = string.Equals(extension, ".vrv", StringComparison.OrdinalIgnoreCase)
                ? LegacySceneBackgroundKind.Video
                : LegacySceneBackgroundKind.Texture;
            return CreateResult(
                options,
                fadeDuration,
                kind,
                Path.GetRelativePath(root, candidate));
        }
        catch (TrustedPlayoutAssetException)
        {
            throw Invalid();
        }
    }

    /// <summary>Restores the original F3-on default, 배경\기본.vrv.</summary>
    public static LegacySceneCueCompositionOptions CreateLegacyDefault(
        PlayoutOptions options,
        int fadeDuration)
    {
        ArgumentNullException.ThrowIfNull(options);
        ValidateCommon(fadeDuration, options);

        try
        {
            var root = RequireTrustedBackgroundDirectory(options);
            var candidate = TrustedPlayoutAssetPath.ResolveRelativeFile(
                root,
                LegacyDefaultBackgroundFileName,
                AllowedExtensions);
            return CreateResult(
                options,
                fadeDuration,
                LegacySceneBackgroundKind.Video,
                Path.GetRelativePath(root, candidate));
        }
        catch (TrustedPlayoutAssetException)
        {
            throw Invalid();
        }
    }

    /// <summary>
    /// Restores the background assigned by MainForm at startup, Cuts\video\기본.vrv.
    /// This is intentionally distinct from the F2/F3 default in the sibling 배경 root.
    /// </summary>
    public static LegacySceneCueCompositionOptions CreateLegacyStartupDefault(
        PlayoutOptions options,
        int fadeDuration)
    {
        ArgumentNullException.ThrowIfNull(options);
        ValidateCommon(fadeDuration, options);

        try
        {
            var root = TrustedPlayoutAssetPath.ValidateRoot(
                options.SceneDirectory?.Trim() ?? string.Empty);
            var candidate = TrustedPlayoutAssetPath.ResolveRelativeFile(
                root,
                LegacyStartupDefaultBackgroundAssetPath,
                AllowedExtensions);
            return CreateResult(
                options,
                fadeDuration,
                LegacySceneBackgroundKind.Video,
                Path.GetRelativePath(root, candidate),
                PlayoutAssetRoot.SceneDirectory);
        }
        catch (TrustedPlayoutAssetException)
        {
            throw Invalid();
        }
    }

    public static bool TryGetTrustedBackgroundDirectory(
        PlayoutOptions options,
        out string directory)
    {
        ArgumentNullException.ThrowIfNull(options);
        directory = string.Empty;
        try
        {
            directory = TrustedPlayoutAssetPath.ValidateRoot(
                RequireConfiguredBackgroundDirectory(options));
            return true;
        }
        catch
        {
            directory = string.Empty;
            return false;
        }
    }

    internal static bool TryGetConfiguredBackgroundDirectory(
        PlayoutOptions options,
        out string directory)
    {
        ArgumentNullException.ThrowIfNull(options);
        directory = string.Empty;
        try
        {
            directory = RequireConfiguredBackgroundDirectory(options);
            return true;
        }
        catch
        {
            directory = string.Empty;
            return false;
        }
    }

    private static string RequireTrustedBackgroundDirectory(PlayoutOptions options) =>
        TrustedPlayoutAssetPath.ValidateRoot(RequireConfiguredBackgroundDirectory(options));

    private static string RequireConfiguredBackgroundDirectory(PlayoutOptions options)
    {
        var configured = options.LegacyBackgroundDirectory?.Trim();
        if (string.IsNullOrEmpty(configured))
        {
            var sceneDirectory = options.SceneDirectory?.Trim();
            if (string.IsNullOrEmpty(sceneDirectory) ||
                !Path.IsPathFullyQualified(sceneDirectory))
            {
                throw new TrustedPlayoutAssetException();
            }

            var cuts = Path.TrimEndingDirectorySeparator(Path.GetFullPath(sceneDirectory));
            var parent = Path.GetDirectoryName(cuts);
            if (string.IsNullOrEmpty(parent))
            {
                throw new TrustedPlayoutAssetException();
            }

            configured = Path.Combine(parent, "배경");
        }

        if (!Path.IsPathFullyQualified(configured) || configured.Any(char.IsControl))
        {
            throw new TrustedPlayoutAssetException();
        }

        return Path.TrimEndingDirectorySeparator(Path.GetFullPath(configured));
    }

    private static LegacySceneCueCompositionOptions CreateResult(
        PlayoutOptions options,
        int fadeDuration,
        LegacySceneBackgroundKind kind,
        string relativePath,
        PlayoutAssetRoot assetRoot = PlayoutAssetRoot.OperatorBackgroundDirectory) => new(
            fadeDuration,
            kind,
            relativePath,
            options.LegacySceneBackgroundVideoLoopCount,
            options.LegacySceneBackgroundVideoLoopInfinite,
            assetRoot);

    private static void ValidateCommon(int fadeDuration, PlayoutOptions options)
    {
        if (fadeDuration is < 0 or > 19 ||
            !Enum.IsDefined(options.LegacySceneBackgroundKind) ||
            options.LegacySceneBackgroundVideoLoopCount is < 0 or > 10_000)
        {
            throw Invalid();
        }
    }

    private static PlayoutConfigurationException Invalid() => new(
        "신뢰 배경 루트 안의 일반 배경 파일을 확인할 수 없습니다.");
}
