using System;
using System.Threading.Tasks;
using RudderSdk.Core;
using UnityEngine;
using RudderSdk.Unity;

namespace RudderSdk.Unity.Samples
{
  public class ScenariosSample : MonoBehaviour
  {
    [SerializeField] string nickname = "Player";
    [SerializeField] string region = "global";
    [SerializeField] string language = "en";
    [SerializeField] string loginEvent = "player_login";
    [SerializeField] string roundEvent = "demo_round_finished";

    readonly SamplePage _page = new SamplePage(
      "Scenarios",
      "Subscribe to scenario effects, trigger an event, then resolve nodes from UI.");

    StoreOfferEffect _offer;
    bool _subscribed;

    void Start()
    {
      _page.Run(this, async () =>
      {
        await Rudder.Initialize().Auth.LoginWithDeviceAsync(region, language, nickname);
        Subscribe();
        _page.SetStatus("Signed in, listening for scenario effects");
        _page.Log("Subscribed to Effects.On*");
      });
    }

    void OnDestroy()
    {
      Unsubscribe();
    }

    void OnGUI()
    {
      _page.Draw(() =>
      {
        GUILayout.BeginHorizontal();
        if (_page.Button("Trigger " + loginEvent))
          _page.Run(this, () => Trigger(loginEvent));
        if (_page.Button("Trigger " + roundEvent))
          _page.Run(this, () => Trigger(roundEvent));
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        if (_page.Button("Buy offer"))
          _page.Run(this, BuyOffer);
        if (_page.Button("Decline offer"))
          DeclineOffer();
        GUILayout.EndHorizontal();
      });
    }

    async Task Trigger(string eventName)
    {
      var client = Rudder.Initialize();
      Subscribe();
      _page.Log("Scenario.TriggerAsync(\"" + eventName + "\")");
      await client.Scenario.TriggerAsync(eventName);
      _page.SetStatus("Triggered " + eventName);
    }

    async Task BuyOffer()
    {
      if (_offer == null)
      {
        _page.SetStatus("No store-offer effect.", true);
        return;
      }

      var client = Rudder.Initialize();
      var storeSlug = _offer.Get("storeSlug", "cozy-camp-shop");
      var store = await client.Stores.GetAsync(storeSlug);
      var offer = store?.Offers != null && store.Offers.Count > 0 ? store.Offers[0] : null;
      if (offer == null)
        throw new InvalidOperationException("Store " + storeSlug + " has no offers.");

      _page.Log("Stores.PurchaseAsync(" + storeSlug + ", " + offer.Id + ")");
      var response = await client.Stores.PurchaseAsync(storeSlug, offer.Id);
      if (response != null && response.Success != true)
        throw new InvalidOperationException(response.Error ?? "Purchase rejected");

      _offer.Purchase();
      _offer = null;
      _page.SetStatus("Offer purchased");
      _page.Log("StoreOfferEffect.Purchase()");
    }

    void DeclineOffer()
    {
      if (_offer == null)
      {
        _page.SetStatus("No store-offer effect.", true);
        return;
      }

      _offer.Decline();
      _offer = null;
      _page.SetStatus("Offer declined");
      _page.Log("StoreOfferEffect.Decline()");
    }

    void Subscribe()
    {
      if (_subscribed || Rudder.State != RudderState.Ready)
        return;

      var effects = Rudder.Client.Effects;
      effects.OnNotification += OnNotification;
      effects.OnStoreOffer += OnStoreOffer;
      effects.OnWait += OnWait;
      effects.OnQuest += OnQuest;
      effects.OnLeaderboard += OnLeaderboard;
      effects.OnBattlePass += OnBattlePass;
      effects.OnBattlePassLevel += OnBattlePassLevel;
      effects.OnScenarioCompleted += OnCompleted;
      effects.OnScenarioFailed += OnFailed;
      _subscribed = true;
    }

    void Unsubscribe()
    {
      if (!_subscribed || Rudder.State != RudderState.Ready)
        return;

      var effects = Rudder.Client.Effects;
      effects.OnNotification -= OnNotification;
      effects.OnStoreOffer -= OnStoreOffer;
      effects.OnWait -= OnWait;
      effects.OnQuest -= OnQuest;
      effects.OnLeaderboard -= OnLeaderboard;
      effects.OnBattlePass -= OnBattlePass;
      effects.OnBattlePassLevel -= OnBattlePassLevel;
      effects.OnScenarioCompleted -= OnCompleted;
      effects.OnScenarioFailed -= OnFailed;
      _subscribed = false;
    }

    void OnNotification(NotificationEffect effect)
    {
      var title = effect.Title;
      var message = effect.Message;
      _page.Log("OnNotification: " + title + " " + message);
      _page.SetOutput(title + "\n" + message);
      effect.Done();
    }

    void OnStoreOffer(StoreOfferEffect effect)
    {
      _offer = effect;
      var storeSlug = effect.Get("storeSlug", "cozy-camp-shop");
      _page.Log("OnStoreOffer: " + storeSlug);
      _page.SetOutput("Store offer from " + storeSlug + "\nUse Buy offer or Decline offer.");
      _page.SetStatus("Store offer waiting");
    }

    void OnWait(WaitEffect effect)
    {
      _page.Log("OnWait until " + effect.DeadlineUtc.ToString("O"));
    }

    void OnQuest(QuestEffect effect)
    {
      _page.Log("OnQuest: " + effect.NodeId);
    }

    void OnLeaderboard(LeaderboardEffect effect)
    {
      _page.Log("OnLeaderboard: " + effect.NodeId);
      effect.End();
    }

    void OnBattlePass(BattlePassEffect effect)
    {
      _page.Log("OnBattlePass: " + effect.NodeId);
    }

    void OnBattlePassLevel(BattlePassLevelEffect effect)
    {
      _page.Log("OnBattlePassLevel: " + effect.NodeId);
    }

    void OnCompleted(ScenarioCompletedEffect effect)
    {
      _page.Log("OnScenarioCompleted: " + effect.RunId);
      _page.SetStatus("Scenario completed");
    }

    void OnFailed(ScenarioFailedEffect failed)
    {
      _page.Log("OnScenarioFailed: " + failed.NodeId + " " + failed.Exception.Message);
      _page.SetStatus(failed.Exception.Message, true);
    }
  }
}
