using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

namespace TwitchInGames {
    public class FollowersRequest {
        public enum PaginationDirection { None, Forward, Backward };

        public string Cursor;
        public PaginationDirection Direction;
        public uint Count;
        private const string helixFollowRootUrl = "https://api.twitch.tv/helix/users/follows";

        public Coroutine<FollowersResponse> Fetch(string clientId, string token, string userId) {
            return new Coroutine<FollowersResponse>(InternalFetch(clientId, token, userId));
        }

        private IEnumerator InternalFetch(string clientId, string token, string userId) {
            // Validate the arguments.
            Utility.CheckArgument(nameof(clientId), clientId);
            Utility.CheckArgument(nameof(userId), userId);

            // Construct the request URL.
            string url = $"{helixFollowRootUrl}?to_id={userId}";
            if(Count != 0) {
                url += $"&first={Count}";
            }
            if(Direction != PaginationDirection.None && !String.IsNullOrEmpty(Cursor)) {
                url += Direction == PaginationDirection.Forward ? "&after=" : "&before=";
                url += Cursor;
            }

            // Create and start a Web request for the followers.
            var www = UnityWebRequest.Get(url);
            if(!String.IsNullOrEmpty(token)) {
                www.SetRequestHeader("Authorization", $"Bearer {token}");
            }
            www.SetRequestHeader("Client-ID", clientId);
            yield return www.SendWebRequest();

            // Check for request failure.
            if(www.isNetworkError || www.isHttpError) {
                Debug.LogError(Utility.FormatMessage("FollowersRequest.Fetch", www.error));
                throw new Exception(www.error);
            }

            // Extract the Helix response.
            var jsonEntity = JsonUtility.FromJson<HelixFollowResponse>(www.downloadHandler.text);

            // Convert the Helix follow into an SDK follow.
            var followResponse = new FollowersResponse(jsonEntity);
            yield return followResponse;
        }
    }

    public class FollowersResponse {
        public List<Follower> Followers;
        public string Cursor;
        public uint TotalCount;

        internal FollowersResponse(HelixFollowResponse jsonEntity) {
            Followers = jsonEntity.data.Select(f => new Follower(f)).ToList();
            Cursor = jsonEntity.pagination.cursor;
            TotalCount = jsonEntity.total;
        }
    }

    public class Follower {
        public string UserId;
        public DateTime FollowedAt;

        internal Follower(HelixFollow follow) {
            UserId = follow.from_id;
            FollowedAt = Utility.StringToDateTime(follow.followed_at).ToUniversalTime();
        }
    }

#pragma warning disable 649 // Field '*' is never assigned to, and will always have its default value *
    [Serializable]
    internal class HelixFollow {
        public string from_id;
        public string to_id;
        public string followed_at;
    }

    [Serializable]
    internal class HelixPagination {
        public string cursor;
    }

    [Serializable]
    internal class HelixFollowResponse {
        public uint total;
        public HelixFollow[] data;
        public HelixPagination pagination;
    }
#pragma warning restore 649
}
