#nullable enable
using System;
using System.Threading.Tasks;
using UnityEngine;

namespace IGP.UnitySDK
{
    public partial class IGPRuntimeManager
    {
        private interface IIGPHostSessionPlatformRuntime : IDisposable
        {
            IGPHostSessionPlatform Platform { get; }
            string TransportName { get; }
            string ConnectionSource { get; }
            string AttachedReason { get; }
            string DetachedReason { get; }
            string LogEndpoint { get; }

            IIGPHostSessionTransport CreateTransport();
            IGPDesktopSessionAttachRequest CreateAttachRequest(int appId);
            Task InitializeSessionAsync();
            Task<bool> RecoverUnavailableSessionAsync(int? appIdOverride);
            Task<bool> AuthorizeAsync();
            void Tick();
            void OnAttachSucceeded();
            void ScheduleAttachRecoveryIfNeeded();
            void ScheduleAuthorizationRecoveryIfNeeded();
        }

        private abstract class IGPHostSessionPlatformRuntimeBase : IIGPHostSessionPlatformRuntime
        {
            protected readonly IGPRuntimeManager Runtime;

            protected IGPHostSessionPlatformRuntimeBase(IGPRuntimeManager runtime)
            {
                Runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
            }

            public abstract IGPHostSessionPlatform Platform { get; }
            public abstract string TransportName { get; }
            public abstract string ConnectionSource { get; }
            public abstract string AttachedReason { get; }
            public abstract string DetachedReason { get; }
            public abstract string LogEndpoint { get; }

            protected bool ShouldAutoAttach =>
                Runtime.initializeRequested &&
                (Runtime.config == null || Runtime.config.desktopSessionAutoAttach);

            public abstract IIGPHostSessionTransport CreateTransport();
            public abstract IGPDesktopSessionAttachRequest CreateAttachRequest(int appId);
            public abstract Task InitializeSessionAsync();
            public abstract Task<bool> RecoverUnavailableSessionAsync(int? appIdOverride);
            public abstract Task<bool> AuthorizeAsync();
            public abstract void Tick();
            public abstract void OnAttachSucceeded();
            public abstract void ScheduleAttachRecoveryIfNeeded();
            public abstract void ScheduleAuthorizationRecoveryIfNeeded();
            public abstract void Dispose();

            protected IGPDesktopSessionAttachRequest CreateCommonAttachRequest(
                int appId,
                string executablePath,
                int processId)
            {
                return new IGPDesktopSessionAttachRequest
                {
                    AppId = appId,
                    ExecutablePath = executablePath,
                    ProcessId = processId,
                    SdkVersion = Runtime.ResolveSdkVersion(),
                    EngineVersion = Application.unityVersion,
                };
            }
        }

        private IIGPHostSessionPlatformRuntime CreateHostSessionPlatformRuntime()
        {
            return config?.hostSessionPlatform == IGPHostSessionPlatform.Mobile
                ? new IGPMobileHostSessionPlatformRuntime(this)
                : new IGPDesktopHostSessionPlatformRuntime(this);
        }
    }
}
