using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using TeamsISO.App.WinUI.ViewModels;
using TeamsISO.App.WinUI.Views;
using TeamsISO.Engine.Controller;
using TeamsISO.Engine.Interop;
using TeamsISO.Engine.Logging;
using TeamsISO.Engine.NdiInterop;
using TeamsISO.Engine.Persistence;
using TeamsISO.Engine.Pipeline;

namespace TeamsISO.App.WinUI;

/// <summary>
/// WinUI 3 entry — brings up MainWindow and wires the engine pipeline.
/// </summary>
public partial class App : Application
{
    private Window? _mainWindow;
    private ILoggerFactory? _loggerFactory;
    private NdiInteropPInvoke? _interop;
    private IsoController? _controller;
    private MainViewModel? _viewModel;

    public App()
    {
        InitializeComponent();
    }

    internal Window? MainWindow => _mainWindow;
    internal MainViewModel? ViewModel => _viewModel;

    protected override void OnLaunched(LaunchActivatedEventArgs args)
    {
        _mainWindow = new MainWindow();
        _mainWindow.Activate();

        _ = WireEngineAsync();
    }

    private async Task WireEngineAsync()
    {
        try
        {
            _loggerFactory = EngineLogging.CreateDefault(LogLevel.Information);
            var logger = _loggerFactory.CreateLogger<App>();
            logger.LogInformation(
                "TeamsISO.App.WinUI starting. Build: {Version}. PID: {Pid}.",
                typeof(App).Assembly.GetName().Version,
                Environment.ProcessId);

            try
            {
                _interop = new NdiInteropPInvoke(_loggerFactory.CreateLogger<NdiInteropPInvoke>());
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "NDI runtime preflight failed");
                return;
            }

            var configPath = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                "TeamsISO", "config.json");
            var configStore = new ConfigStore(configPath, _loggerFactory.CreateLogger<ConfigStore>());

            var probe = new NdiRuntimeProbe(_interop, NdiVersion.ExpectedRuntimeVersionPrefix);
            var scaler = new ManagedNearestNeighborFrameScaler();

            var loggerFactoryRef = _loggerFactory;
            var interopRef = _interop;
            IsoPipeline PipelineFactory(IsoPipelineConfig config)
            {
                var clock = new PeriodicTimerFrameClock(config.Settings.FramerateHz);
                return new IsoPipeline(
                    config, interopRef, scaler, clock,
                    ExponentialBackoff.Default,
                    (delay, ct) => Task.Delay(delay, ct),
                    loggerFactoryRef);
            }

            _controller = new IsoController(
                _interop, PipelineFactory, configStore, probe, _loggerFactory);

            var dispatcher = DispatcherQueue.GetForCurrentThread();
            _viewModel = new MainViewModel(_controller, dispatcher);

            if (_mainWindow is MainWindow mw)
            {
                mw.AttachViewModel(_viewModel);
            }

            await _viewModel.InitializeAsync(CancellationToken.None);

            logger.LogInformation("Engine wired. Discovery active. Awaiting Teams participants.");
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine($"Engine wiring failed: {ex}");
        }
    }
}
