using QtCNETAPI.Dtos.Room;
using QtCNETAPI.Dtos.User;
using QtCNETAPI.Enums;
using QtCNETAPI.Models;
using QtCNETAPI.Schema;
using RestSharp;
using System.IdentityModel.Tokens.Jwt;
using System.Text.Json;

namespace QtCNETAPI.Services.ApiService
{
    public class ApiService : IApiService
    {
        private User? user;
        private RestClient _client;
        private LoggingService _loggingService;

        private CredentialService _credService = new();

        internal string? sessionToken;
        internal string apiUri;

        public event EventHandler? OnCurrentUserUpdate;

        public string? SessionToken
        {
            get { return sessionToken; }
            set { sessionToken = value; }
        }

        public User? CurrentUser
        {
            get { return user; }
        }

        public ApiService(string apiUrl, LoggingService loggingService)
        {
            apiUri = apiUrl;
            _loggingService = loggingService;
            _client = new RestClient(apiUri);
        }

        public async Task<ServiceResponse<string>> PingServerAsync()
        {
            var serviceResponse = new ServiceResponse<string>();

            try
            {
                var request = new RestRequest("general/ping");
                var response = await _client.GetAsync<string>(request);

                if (response != null)
                {
                    if (response != "Pong!") serviceResponse.Success = false;
                    else serviceResponse.Success = true;
                }
                else serviceResponse.Success = false;
            } catch (HttpRequestException ex)
            {
                serviceResponse.Success = false;
                serviceResponse.Message = ex.Message;
            }
            
            return serviceResponse;
        }

        public async Task<ServiceResponse<List<UserInformationDto>>> GetAllUsersAsync()
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<List<UserInformationDto>>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var request = new RestRequest("users/all")
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.GetAsync<ServiceResponse<List<UserInformationDto>>>(request);

            if (response != null || response!.Data != null)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }
            else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API didn't respond with users.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<List<UserInformationDto>>> GetOnlineUsersAsync()
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<List<UserInformationDto>>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var request = new RestRequest("users/users-online")
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.GetAsync<ServiceResponse<List<UserInformationDto>>>(request);

            if (response != null || response!.Data != null) 
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            } else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API didn't respond with online users.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<UserInformationDto>> GetUserInformationAsync(string id)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<UserInformationDto>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var request = new RestRequest($"users/user-info")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("id", id);
            var response = await _client.GetAsync<ServiceResponse<UserInformationDto>>(request);

            if(response != null || response!.Data != null)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            } else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API did not return user information.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<UserInformationDto>> UpdateUserInformationAsync(UserUpdateInformationDto request)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<UserInformationDto>();

            var restRequest = new RestRequest("users/update")
                .AddJsonBody(request)
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.PutAsync<ServiceResponse<UserInformationDto>>(restRequest);

            if(response != null || response!.Data != null)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;

                // anything that changes the user should tell the api service to set it again
                await SetCurrentUser();
                OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
            } else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API never responded.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<string>> UpdateUserProfilePic(string filePath)
        {
            var serviceResponse = new ServiceResponse<string>();

            try
            {
                var restRequest = new RestRequest($"users/upload-profile-pic")
                    .AddQueryParameter("userId", CurrentUser!.Id)
                    .AddHeader("Authorization", $"Bearer {SessionToken}")
                    .AddFile("file", filePath);
                var response = await _client.PostAsync<ServiceResponse<string>>(restRequest);

                if (response != null && response.Success != false)
                {
                    serviceResponse.Success = true;
                    serviceResponse.Data = response.Data;

                    // anything that changes the user should tell the api service to set it again
                    await SetCurrentUser();
                    OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
                }
                else
                {
                    serviceResponse.Success = false;
                    serviceResponse.Data = "Upload Failed.";
                }
            } catch (JsonException)
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "Profile Pictures Can Only Be Less Then 3 MB In Size.";
            } catch (HttpRequestException ex)
            {
                serviceResponse.Success = false;
                serviceResponse.Data = ex.Message;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<byte[]>> GetUserProfilePic(string userId)
        {
            var serviceResponse = new ServiceResponse<byte[]>();
            try
            {
                var restRequest = new RestRequest($"users/profile-pic/{userId}")
                    .AddHeader("Authorization", $"Bearer {SessionToken}");
                var response = await _client.GetAsync(restRequest);

                if (response != null)
                {
                    serviceResponse.Success = true;
                    serviceResponse.Data = response.RawBytes;
                }
                else
                {
                    serviceResponse.Success = false;
                    serviceResponse.Message = "No Profile Picture Received.";
                }

                return serviceResponse;
            } catch (HttpRequestException ex)
            {
                serviceResponse.Success = false;
                serviceResponse.Message = ex.Message;
                return serviceResponse;
            }
        }

        public async Task<ServiceResponse<string>> LoginAsync(UserLoginDto userLoginDto)
        {
            var serviceResponse = new ServiceResponse<string>();

            try
            {
                if (string.IsNullOrWhiteSpace(userLoginDto.Email) || string.IsNullOrWhiteSpace(userLoginDto.Password))
                {
                    serviceResponse.Success = false;
                    serviceResponse.Message = "Email or Password cannot be null.";
                }

                var request = new RestRequest("auth/login")
                    .AddJsonBody(userLoginDto);
                var response = await _client.PostAsync<ServiceResponse<string>>(request);

                if (response != null)
                {
                    if (response.Data != null && response.Success)
                    {
                        SessionToken = response.Data!;

                        var user = await SetCurrentUser();

                        serviceResponse.Success = true;
                        if (response.Message != null) serviceResponse.Message = response.Message;
                        serviceResponse.Data = response.Message;
                    }
                    else
                    {
                        serviceResponse.Success = false;
                        serviceResponse.Message = response.Message;
                    }
                }
            } catch (Exception ex)
            {
                serviceResponse.Success = false;
                serviceResponse.Message = ex.Message;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<bool>> ResendVerificationEmail(string email)
        {
            var serviceResponse = new ServiceResponse<bool>();

            var restRequest = new RestRequest($"auth/resend-verification-email")
                .AddQueryParameter("email", email);
            var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);

            if (response != null)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }
            else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API never responded.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<bool>> SendPasswordResetEmail(string email)
        {
            var serviceResponse = new ServiceResponse<bool>();

            var restRequest = new RestRequest($"auth/request-password-reset")
                .AddQueryParameter("email", email);
            var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);

            if (response != null)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }
            else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API never responded.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<bool>> ResetPassword(UserPasswordResetDto request)
        {
            var serviceResponse = new ServiceResponse<bool>();

            var restRequest = new RestRequest($"auth/reset-password")
                .AddJsonBody(request);
            var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);

            if (response != null)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }
            else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API never responded.";
            }

            return serviceResponse;
        }

        public async Task<User> SetCurrentUser()
        {
            var userRequest = new RestRequest("users/user-authorized")
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var userResponse = await _client.GetAsync<ServiceResponse<User>>(userRequest);

            if (userResponse != null && userResponse.Success && userResponse.Data != null)
            {
                user = userResponse.Data;

                _loggingService.LogString($"Current User's Status Is {userResponse.Data.Status}");

                return userResponse.Data;
            } else
            {
                throw new NullReferenceException("Current User could not be set.");
            }
        }

        public async Task<ServiceResponse<User>> RefreshLogin(string refreshToken)
        {
            var serviceResponse = new ServiceResponse<User>();

            try
            {
                if (string.IsNullOrEmpty(refreshToken))
                {
                    serviceResponse.Success = false;
                    serviceResponse.Message = "No Refresh Token Specified.";
                }

                var request = new RestRequest("auth/refresh")
                    .AddQueryParameter("token", refreshToken);
                var response = await _client.PostAsync<ServiceResponse<string>>(request);

                if (response != null && response.Success != false)
                {
                    SessionToken = response.Data;

                    if (user == null)
                    {
                        var user = await SetCurrentUser();

                        serviceResponse.Success = true;
                        serviceResponse.Data = user;
                    }

                    serviceResponse.Success = true;
                    serviceResponse.Data = CurrentUser;
                }
                else
                {
                    serviceResponse.Success = false;
                    serviceResponse.Message = "API didn't respond with a session token.";
                }
            } catch (Exception ex)
            {
                serviceResponse.Success = false;
                serviceResponse.Message = ex.Message;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<string>> RefreshSessionIfInvalid()
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var refToken = _credService.GetAccessToken(); // fuck CA1416, if this is being ran on linux it should just crash (theoretically)

            if (refToken == null)
            {
                // treat as session expired
                return new ServiceResponse<string> { Success = false, Message = "Refresh Token Not Found. Session Expired." };
            }

            JwtSecurityToken token = tokenHandler.ReadJwtToken(SessionToken);

            if(DateTime.Compare(DateTime.UtcNow, token.ValidTo) > 0)
            {
                var result = await RefreshLogin(refToken);

                if (result == null || result.Success == false)
                {
                    return new ServiceResponse<string> { Success = false, Message = "Session Expired." }; // logging in again should overwrite old token
                } else return new ServiceResponse<string> { Success = true, Data = refToken };
            } else return new ServiceResponse<string> { Success = true, Data = refToken };
        }

        public async Task<ServiceResponse<User>> RegisterAsync(UserDto userDto)
        {
            var serviceResponse = new ServiceResponse<User>();

            if (string.IsNullOrEmpty(userDto.Username) || string.IsNullOrEmpty(userDto.Password) || string.IsNullOrEmpty(userDto.Email))
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "Incomplete UserDto.";
            }

            var request = new RestRequest("auth/register")
                .AddJsonBody(userDto);
            var response = await _client.PostAsync<ServiceResponse<User>>(request);

            if (response != null || response!.Success == true)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            } else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API never responded with created user.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<Room>> CreateRoomAsync(RoomDto request)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<Room>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest($"rooms/create-room?userId={user!.Id}")
                .AddJsonBody(request)
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.PostAsync<ServiceResponse<Room>>(restRequest);

            if(response != null || response!.Data != null)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            } else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API never responded with created room.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<List<Room>>> GetAllRoomsAsync()
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<List<Room>>();

            if(SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var request = new RestRequest("rooms/get-all-rooms")
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.GetAsync<ServiceResponse<List<Room>>>(request);

            if (response != null || response!.Data != null)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }
            else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API never responded with rooms.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<Room>> DeleteRoomAsync(string roomId)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<Room>();

            if(SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var request = new RestRequest($"rooms/delete-room?roomId={roomId}")
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.DeleteAsync<ServiceResponse<Room>>(request);

            if (response != null || response!.Data != null)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            } else
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API never responded.";
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<List<Contact>>> GetCurrentUserContacts()
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<List<Contact>>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var request = new RestRequest("contacts/get-user-contacts")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddJsonBody(CurrentUser!);
            var response = await _client.GetAsync<ServiceResponse<List<Contact>>>(request);

            if (response == null)
            {
                serviceResponse.Success = false;
                serviceResponse.Message = "API didn't respond.";

                return serviceResponse;
            }

            if (response.Message == "User Has No Contacts.")
            {
                serviceResponse.Success = true;
                serviceResponse.Message = "No Contacts Found.";
            }

            if (response.Success == true)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<Contact>> AddContactToCurrentUser(string userId)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<Contact>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("contacts/add-contact")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("ownerId", CurrentUser!.Id)
                .AddQueryParameter("userId", userId);
            var response = await _client.PostAsync<ServiceResponse<Contact>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<bool>> AcceptContactRequest(string userId)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<bool>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("contacts/approve-contact")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("ownerId", CurrentUser!.Id)
                .AddQueryParameter("userId", userId);
            var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<Contact>> RemoveContactFromCurrentUser(string userId)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<Contact>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("contacts/remove-contact")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("userId", userId);
            var response = await _client.DeleteAsync<ServiceResponse<Contact>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<int>> AddCurrencyToCurrentUser(int amount, bool isSpinClaim)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<int>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("users/update-user-currency")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("amount", amount)
                .AddQueryParameter("isSpinClaim", isSpinClaim);
            var response = await _client.PostAsync<ServiceResponse<int>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;

                // anything that changes the user should tell the api service to set it again
                await SetCurrentUser();
                OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<int>> GetCurrentStockPrice()
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<int>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("games/stock-market/current-price")
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.GetAsync<ServiceResponse<int>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<UserStockActionResultDto>> BuyStock(int amount)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<UserStockActionResultDto>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("games/stock-market/buy-stock")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("amount", amount);
            var response = await _client.PostAsync<ServiceResponse<UserStockActionResultDto>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;

                // anything that changes the user should tell the api service to set it again
                await SetCurrentUser();
                OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<UserStockActionResultDto>> SellStock(int amount)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<UserStockActionResultDto>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("games/stock-market/sell-stock")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("amount", amount);
            var response = await _client.PostAsync<ServiceResponse<UserStockActionResultDto>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;

                // anything that changes the user should tell the api service to set it again
                await SetCurrentUser();
                OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<int>> GetRandomNumber()
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<int>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("games/number-guess/get-number")
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.GetAsync<ServiceResponse<int>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<NumberGuessResult>> GuessRandomNumber(int original, int guess)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<NumberGuessResult>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("games/number-guess/guess-number")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("original", original)
                .AddQueryParameter("guess", guess);
            var response = await _client.GetAsync<ServiceResponse<NumberGuessResult>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<List<StoreItem>>> GetStoreItems()
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<List<StoreItem>>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("store/all-items")
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.GetAsync<ServiceResponse<List<StoreItem>>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<StoreItem>> GetStoreItem(int id)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<StoreItem>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("store/item")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("id", id);
            var response = await _client.GetAsync<ServiceResponse<StoreItem>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<bool>> BuyStoreItem(int id)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<bool>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("store/buy-item")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("id", id);
            var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;

                // anything that changes the user should tell the api service to set it again
                await SetCurrentUser();
                OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<List<OwnedStoreItem>>> GetOwnedStoreItems()
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<List<OwnedStoreItem>>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("store/bought-items")
                .AddHeader("Authorization", $"Bearer {SessionToken}");
            var response = await _client.GetAsync<ServiceResponse<List<OwnedStoreItem>>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<OwnedStoreItem>> GetOwnedStoreItem(int id)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<OwnedStoreItem>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("store/bought-item")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("id", id);
            var response = await _client.GetAsync<ServiceResponse<OwnedStoreItem>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }

        public async Task<ServiceResponse<User>> DeleteUserById(string id)
        {
            await RefreshSessionIfInvalid();

            var serviceResponse = new ServiceResponse<User>();

            if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");

            var restRequest = new RestRequest("users/delete-user")
                .AddHeader("Authorization", $"Bearer {SessionToken}")
                .AddQueryParameter("id", id);
            var response = await _client.DeleteAsync<ServiceResponse<User>>(restRequest);

            if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; }

            if (response.Success)
            {
                serviceResponse.Success = true;
                serviceResponse.Data = response.Data;
            }

            return serviceResponse;
        }
    }
}
