using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RecruitmentTesting.Api.Models;

namespace RecruitmentTesting.Api.Client
{
    public class ApiWrapper : IDisposable
    {
        private HttpClient client;

        public ApiWrapper()
        {
            this.client = new HttpClient()
            {
                BaseAddress = new Uri("https://testdome.com/api/v1/")
            };
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }

        public async Task Authenticate(string email, string apiPassword)
        {
            string accessToken = await GetAccessToken(email, apiPassword);
            if (String.IsNullOrEmpty(accessToken))
                throw new InvalidOperationException("Authentication failed!");
            else
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
        }

        private async Task<string> GetAccessToken(string email, string apiPassword)
        {
            var content = new FormUrlEncodedContent(new[]
            {
                new KeyValuePair<string, string>("grant_type", "password"),
                new KeyValuePair<string, string>("username", email),
                new KeyValuePair<string, string>("password", apiPassword)
            });

            HttpResponseMessage response = await client.PostAsync("Token", content);
            string result = response.Content.ReadAsStringAsync().Result;
            var token = JObject.Parse(result)["access_token"];
            if (token == null)
                throw new InvalidOperationException(result);
            else
                return token.ToString();
        }

        public async Task<IEnumerable<Test>> GetTestsAsync()
        {
            HttpResponseMessage response = await client.GetAsync("tests");
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsAsync<IEnumerable<Test>>();
        }

        public async Task<IEnumerable<Candidate>> GetCandidatesAsync(int testId)
        {
            HttpResponseMessage response = await client.GetAsync("candidates?testId=" + testId);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsAsync<IEnumerable<Candidate>>();
        }

        public async Task<InviteCandidatesResult> InviteCandidate(int testId, params string[] candidates)
        {
            InviteCandidatesArgs invitation = new InviteCandidatesArgs()
            {
                TestId = testId,
                CandidateEmails = candidates
            };

            string jsonData = JsonConvert.SerializeObject(invitation);
            HttpResponseMessage response = await client.PostAsync("candidates/invitecandidates", new StringContent(jsonData, Encoding.Unicode, "application/json"));
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsAsync<InviteCandidatesResult>();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.client != null)
                {
                    this.client.Dispose();
                    this.client = null;
                }
            }
        }
    }
}
