using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using Windows.Graphics.Capture;

namespace ytLive.Services;

/// <summary>
/// Turns a capture key ("monitor:&lt;n&gt;", "window:&lt;hwnd&gt;", "picker:&lt;...&gt;")
/// into a live <see cref="IScreenCaptureSource"/>, and hosts the OS
/// GraphicsCapturePicker used by "Change Capture…". Picker picks are transient:
/// the picked GraphicsCaptureItem has no HWND/monitor identity, so a
/// "picker:" key resolves only within the current session and re-detection
/// takes over after a reload (documented v1 limit).
/// </summary>
public sealed class ScreenCaptureSourceFactory
{
    private readonly Func<IntPtr> _ownerHwndProvider;
    private readonly Dictionary<string, GraphicsCaptureItem> _picked = new();
    private readonly object _gate = new();

    public ScreenCaptureSourceFactory(Func<IntPtr> ownerHwndProvider)
    {
        _ownerHwndProvider = ownerHwndProvider;
    }

    /// <summary>Creates the source for a persisted key, or null when it can't be resolved.</summary>
    public IScreenCaptureSource? Resolve(string key)
    {
        if (key.StartsWith("monitor:", StringComparison.OrdinalIgnoreCase))
        {
            var indexText = key.AsSpan("monitor:".Length);
            if (int.TryParse(indexText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var index))
                return ScreenCaptureFrameSource.CreateForMonitor(index);
            return null;
        }

        if (key.StartsWith("window:", StringComparison.OrdinalIgnoreCase))
        {
            var hexText = key.AsSpan("window:".Length);
            if (long.TryParse(hexText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var hwnd))
                return ScreenCaptureFrameSource.CreateForWindow(new IntPtr(hwnd));
            return null;
        }

        if (key.StartsWith("picker:", StringComparison.OrdinalIgnoreCase))
        {
            lock (_gate)
                return _picked.TryGetValue(key, out var item)
                    ? ScreenCaptureFrameSource.CreateForPicker(key, item)
                    : null;
        }

        return null;
    }

    /// <summary>
    /// Shows the OS capture picker (must run on the UI thread, owner window set
    /// via IInitializeWithWindow). Returns the session key, or null if cancelled.
    /// </summary>
    public async Task<string?> PickAsync()
    {
        var picker = new GraphicsCapturePicker();
        CaptureInterop.SetWindowOwner(picker, _ownerHwndProvider());
        var item = await picker.PickSingleItemAsync();
        if (item == null) return null;

        var key = $"picker:{item.DisplayName}";
        lock (_gate)
            _picked[key] = item;
        return key;
    }
}
