using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using UnityEngine.UI;

namespace TwitchInGames.Test {
    public class AuthTest : MonoBehaviour {
        public InputField ClientIdInput;
        public InputField RedirectUriInput;
        public InputField ScopeInput;
        public Text AccessTokenText;
        public Text RefreshTokenText;
        private const string clientId = "05zrlud5jr2b73vijreb681r505eox";
        private const string hostName = "192.168.43.102";
        private const string redirectUri = "http://" + hostName + ":27077/auth";
        private ServerAuth serverAuth;
        private Socket socket;

        private void Start() {
            serverAuth = new ServerAuth();
            ClientIdInput.text = clientId;
            RedirectUriInput.text = redirectUri;
            ScopeInput.text = "user:read:email";
        }

        private void OnDestroy() {
            if(socket != null) {
                socket.Close();
                socket = null;
            }
        }

        public void StartServerAuth() {
            StartCoroutine(DoServerAuth());
        }

        private IEnumerator DoServerAuth() {
            // Connect to the "server".
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
            socket.Connect(hostName, 50537);

            // Start the server authentication flow (flow one).
            var state = serverAuth.StartAuth(ClientIdInput.text, RedirectUriInput.text, new[] { ScopeInput.text });

            // Send the state to the "server".  It will use it to validate the
            // Twitch server authentication response.
            var bytes = Encoding.ASCII.GetBytes(state);
            SocketError socketError;
            AsyncCallback sendCallback = (IAsyncResult result) => {
                socket.EndSend(result, out socketError);
            };
            var sendResult = socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, out socketError, sendCallback, null);
            if(!sendResult.CompletedSynchronously) {
                yield return new WaitUntil(() => sendResult.IsCompleted);
            }
            if(socketError != SocketError.Success) {
                throw new Exception(String.Format("send failed; error {0}", socketError));
            }
            socket.Shutdown(SocketShutdown.Send);

            // Receive the access and refresh tokens from the "server".
            bytes = new byte[888];
            int n = 0;
            AsyncCallback receiveCallback = (IAsyncResult result) => {
                n = socket.EndReceive(result, out socketError);
            };
            var receiveResult = socket.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None, out socketError, receiveCallback, null);
            if(!receiveResult.CompletedSynchronously) {
                yield return new WaitUntil(() => receiveResult.IsCompleted);
            }
            if(socketError != SocketError.Success) {
                throw new Exception(String.Format("receive failed; error {0}", socketError));
            }
            var s = Encoding.ASCII.GetString(bytes, 0, n);
            var parts = s.Split('\t');
            var accessToken = "Access Token: " + parts[0];
            AccessTokenText.text = accessToken;
            var refreshToken = "Refresh Token: " + parts[1];
            RefreshTokenText.text = refreshToken;

            // Complete the server authentication by setting the tokens.
            serverAuth.Finish(accessToken, refreshToken);
            socket.Close();
            socket = null;
        }
    }
}
