// Copyright (c) 2026 EzAdmin. All rights reserved.
// Licensed under the EzAdmin Client License. See LICENSE-CLIENT.txt.

using System;
using UnityEngine;

namespace EzAdmin.Client
{

    public static class EzAdminLink
    {

        public const int CodeLength = EzAdminCode.Length;

        public static bool IsLinked { get; private set; }

        public static string DiscordName { get; private set; } = "";

        public static bool IsBusy { get; private set; }

        public static string Status { get; private set; } = "";

        public static event Action<string> Linked;

        public static event Action<string> StatusChanged;

        public static string Clean(string raw)
        {

            return EzAdminCode.CleanPartial(raw);
        }

        public static bool IsComplete(string raw)
        {
            return EzAdminCode.IsComplete(raw);
        }

        public static void Redeem(string code, Action<bool, string> onComplete = null)
        {
            var client = EzAdminClient.Instance;
            if (client == null)
            {
                Finish(false, "EzAdmin is not set up in this scene.", onComplete);
                Debug.LogError("EzAdminLink: there is no EzAdminClient in the scene. " +
                               "GameObject › EzAdmin › Link Screen adds one.");
                return;
            }
            if (!client.IsSignedIn)
            {
                Finish(false, "Still signing you in. Try again in a moment.", onComplete);
                return;
            }
            if (!IsComplete(code))
            {
                Finish(false, "Enter all " + CodeLength + " characters.", onComplete);
                return;
            }
            if (IsBusy)
            {
                onComplete?.Invoke(false, "Still checking the last code.");
                return;
            }

            IsBusy = true;
            SetStatus("Checking your code...");
            client.RedeemLinkCode(Clean(code), (ok, message) =>
            {
                IsBusy = false;
                SetStatus(message);
                if (ok)
                {
                    MarkLinked("");
                    Check();
                }
                onComplete?.Invoke(ok, message);
            });
        }

        public static void Check(Action<bool, string> onComplete = null)
        {
            var client = EzAdminClient.Instance;
            if (client == null || !client.IsSignedIn)
            {
                onComplete?.Invoke(IsLinked, DiscordName);
                return;
            }
            client.RefreshLinkStatus((linked, discordName) =>
            {
                if (linked)
                {
                    MarkLinked(discordName);
                }
                onComplete?.Invoke(linked, discordName ?? "");
            });
        }

        public static void WhenLinked(Action<string> action)
        {
            if (action == null)
            {
                return;
            }
            if (IsLinked)
            {
                action(DiscordName);
                return;
            }
            Action<string> once = null;
            once = name =>
            {
                Linked -= once;
                action(name);
            };
            Linked += once;
        }

        public static void SetStatus(string message)
        {
            Status = message ?? "";
            StatusChanged?.Invoke(Status);
        }

        private static void MarkLinked(string discordName)
        {
            bool first = !IsLinked;
            IsLinked = true;
            if (!string.IsNullOrEmpty(discordName))
            {
                DiscordName = discordName;
            }
            SetStatus(string.IsNullOrEmpty(DiscordName)
                ? "Linked to Discord. You're all set."
                : "Linked to Discord as " + DiscordName + ". You're all set.");
            if (first || !string.IsNullOrEmpty(discordName))
            {
                Linked?.Invoke(DiscordName);
            }
        }

        private static void Finish(bool ok, string message, Action<bool, string> onComplete)
        {
            SetStatus(message);
            onComplete?.Invoke(ok, message);
        }

        public static void Reset()
        {
            IsLinked = false;
            DiscordName = "";
            IsBusy = false;
            SetStatus("");
        }

        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
        private static void ResetOnPlay()
        {
            IsLinked = false;
            DiscordName = "";
            IsBusy = false;
            Status = "";
            Linked = null;
            StatusChanged = null;
        }
    }
}
