using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

namespace RudderSdk.Unity.Samples
{
  sealed class SamplePage
  {
    const int MaxLogLines = 40;

    readonly string _title;
    readonly string _subtitle;
    readonly List<string> _logLines = new List<string>();
    string _status = "Idle";
    bool _error;
    string _output = string.Empty;
    bool _busy;
    Vector2 _outputScroll;
    Vector2 _logScroll;
    GUIStyle _titleStyle;
    GUIStyle _bodyStyle;
    GUIStyle _statusStyle;

    public SamplePage(string title, string subtitle)
    {
      _title = title;
      _subtitle = subtitle;
    }

    public void Draw(Action body)
    {
      EnsureStyles();
      const float pad = 16f;
      GUILayout.BeginArea(new Rect(pad, pad, Screen.width - pad * 2f, Screen.height - pad * 2f));
      GUILayout.Label(_title, _titleStyle);
      GUILayout.Label(_subtitle, _bodyStyle);
      _statusStyle.normal.textColor = _error ? new Color(1f, 0.45f, 0.4f) : Color.white;
      GUILayout.Label(_status, _statusStyle);
      GUILayout.Space(8f);

      var enabled = GUI.enabled;
      GUI.enabled = enabled && !_busy;
      body();
      GUI.enabled = enabled;

      if (!string.IsNullOrEmpty(_output))
      {
        GUILayout.Space(8f);
        _outputScroll = GUILayout.BeginScrollView(_outputScroll, GUILayout.MinHeight(120f));
        GUILayout.Label(_output, _bodyStyle);
        GUILayout.EndScrollView();
      }

      GUILayout.Space(8f);
      GUILayout.Label("Log", _titleStyle);
      _logScroll = GUILayout.BeginScrollView(_logScroll, GUILayout.MinHeight(100f));
      if (_logLines.Count == 0)
        GUILayout.Label("(empty)", _bodyStyle);
      else
        GUILayout.Label(string.Join("\n", _logLines), _bodyStyle);
      GUILayout.EndScrollView();
      GUILayout.EndArea();
    }

    public bool Button(string text)
    {
      return GUILayout.Button(text, GUILayout.Height(28f), GUILayout.MaxWidth(280f));
    }

    public void Label(string text)
    {
      GUILayout.Label(text, _bodyStyle);
    }

    public void SetStatus(string text, bool error = false)
    {
      _status = text;
      _error = error;
    }

    public void SetOutput(string text)
    {
      _output = text ?? string.Empty;
    }

    public void Log(string line)
    {
      _logLines.Insert(0, DateTime.Now.ToString("HH:mm:ss") + "  " + line);
      if (_logLines.Count > MaxLogLines)
        _logLines.RemoveAt(_logLines.Count - 1);
    }

    public async void Run(MonoBehaviour host, Func<Task> action)
    {
      if (_busy)
        return;

      _busy = true;
      SetStatus("Working…");
      try
      {
        await action();
      }
      catch (Exception exception)
      {
        await Awaitable.MainThreadAsync();
        if (host == null)
          return;

        SetStatus(exception.Message, true);
        Log(exception.Message);
      }
      finally
      {
        _busy = false;
      }
    }

    void EnsureStyles()
    {
      if (_titleStyle != null)
        return;

      _titleStyle = new GUIStyle(GUI.skin.label)
      {
        fontSize = 20,
        fontStyle = FontStyle.Bold,
        wordWrap = true
      };
      _titleStyle.normal.textColor = Color.white;

      _bodyStyle = new GUIStyle(GUI.skin.label)
      {
        fontSize = 14,
        wordWrap = true
      };
      _bodyStyle.normal.textColor = Color.white;

      _statusStyle = new GUIStyle(_bodyStyle);
    }
  }
}
