using System;
using System.Collections.Generic;
using System.Text;
using static BaroSeeSDK.AuthenticationProvider;

namespace BaroSeeSDK
{
    public interface IAuthenticationProvider
    {
        event AccessTokenChangedEvent OnAccessTokenChanged;        
        AccessToken CurrentAccessToken { get; }
        AccessToken GetAcessToken(string publicKey, string privateKey, ErrorHandler errorHandler = null);
        AccessToken RenewAccessToken(ErrorHandler errorHandler = null);
        bool UnsubscribeAccessToken(ErrorHandler errorHandler = null);
        object User(ErrorHandler errorHandler = null);
    }

    public class AuthenticationProvider: IAuthenticationProvider
    {
        public AccessToken CurrentAccessToken { get; internal set; }
        private class TokenInfo
        {
            public string access_token { get; set; }
            public string token_type { get; set; }
            public int expires_in { get; set; }
        }
        public AuthenticationProvider(string pubicKey, string privateKey, ErrorHandler errorHandler = null) {
            Configure(GetAcessToken(pubicKey, privateKey), errorHandler);
        }

        public AuthenticationProvider(AccessToken token, ErrorHandler errorHandler = null) {
            Configure(token, errorHandler);
        }

        private void Configure(AccessToken token, ErrorHandler errorHandler = null) {
            this.CurrentAccessToken = token;
            if (token == null)
            {
                if (errorHandler != null)
                    errorHandler.Invoke("AuthenticationProvider", System.Net.HttpStatusCode.Unauthorized, "Token is null or empty");
                else
                    throw new ArgumentException("Invalid token");
            }
        }

        public AccessToken GetAcessToken(string publicKey, string privateKey, ErrorHandler errorHandler = null)
        {         
            ApiEntry entry = BaroSeeService.Apis[BaroSeeService.ApiEntries.auth_token];
            List<KeyValuePair<string, string>> data = new List<KeyValuePair<string, string>>();
            data.Add(new KeyValuePair<string, string>("client_id", publicKey));
            data.Add(new KeyValuePair<string, string>("client_secret", privateKey));
            data.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
            TokenInfo value = ApiCaller.Execute<TokenInfo>(entry, data, new ErrorHandler[] { errorHandler }, "application/x-www-form-urlencoded");
            CurrentAccessToken = value != null? new AccessToken()
            {
                Value = value.access_token,
                ExpiredAt = DateTime.UtcNow.AddMinutes(value.expires_in)
            } : null;

            if (OnAccessTokenChanged != null) OnAccessTokenChanged.Invoke(CurrentAccessToken);
            return CurrentAccessToken;
        }

        public AccessToken RenewAccessToken(ErrorHandler errorHandler = null)
        {
            return null;
        }

        public bool UnsubscribeAccessToken(ErrorHandler errorHandler = null)
        {
            bool result = false;
            ApiEntry entry = BaroSeeService.Apis[BaroSeeService.ApiEntries.auth_token];
            result = ApiCaller.Execute<bool>(CurrentAccessToken.Value, entry, null, new ErrorHandler[] { errorHandler });
            return result;
        }

        public object User(ErrorHandler errorHandler = null)
        {
            //ApiEntry entry = BaroSeeSDK.Apis[BaroSeeSDK.ApiEntries.auth_token];            
            //result = ApiCaller.Execute<AccessToken>(token.Value, entry, null, new BaroSeeSDK.ErrorHandler[] { errorHandler });
            //return result;
            return null;
        }

        #region events
        public event AccessTokenChangedEvent OnAccessTokenChanged;
        #endregion
        #region delegates
        public delegate void AccessTokenChangedEvent(AccessToken token);
        #endregion
    }
}
