func generateArtistsString(artists []spotifyArtist) string {
	logger.Log("GenerateArtistsString", "Starting...")
	var creators = []string{}
	for _, artist := range artists {
		creators = append(creators, artist.Name)
	}
	logger.Log("GenerateArtistsString", "Successfully appended artists.")
	return strings.Join(creators, ", ")
}
generateArtistsString takes in a list of artists and returns a comma separated string
package getspotifymedia
import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
	"cloud.google.com/go/firestore"
	"github.com/pixelogicdev/gruveebackend/pkg/firebase"
	"github.com/pixelogicdev/gruveebackend/pkg/social"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
func initWithEnv() error {
	var currentProject string
	if os.Getenv("ENVIRONMENT") == "DEV" {
		currentProject = os.Getenv("FIREBASE_PROJECTID_DEV")
	} else if os.Getenv("ENVIRONMENT") == "PROD" {
		currentProject = os.Getenv("FIREBASE_PROJECTID_PROD")
	}
	httpClient = &http.Client{}
	client, err := firestore.NewClient(context.Background(), currentProject)
	if err != nil {
		return fmt.Errorf("CreateUser [Init Firestore]: %v", err)
	}
	firestoreClient = client
	return nil
}
func getCreds() (*firebase.FirestoreSpotifyAuthToken, error) {
	logger.Log("GetCreds", "Starting...")
	if os.Getenv("SPOTIFY_CLIENTID") == "" || os.Getenv("SPOTIFY_SECRET") == "" {
		return nil, fmt.Errorf("getSpotifyMedia [Check Env Props]: PROPS NOT HERE")
	}
	logger.Log("GetCreds", "Found Spotify ClientID in env variables")
	authToken, authTokenErr := fetchToken()
	if authTokenErr != nil {
		return nil, authTokenErr
	}
	logger.Log("GetCreds", "Received token.")
	if authToken != nil {
		logger.Log("GetCreds", "Checking to see if token needs to be refreshed")
		latestCreds, refreshAuthTokenErr := refreshAuthToken(*authToken)
		if refreshAuthTokenErr != nil {
			return nil, refreshAuthTokenErr
		}
		logger.Log("GetCreds", "Auth token refresh complete.")
		return latestCreds, nil
	}
	logger.Log("GetCreds", "No auth token found.")
	newAuthToken, newAuthTokenErr := generateAuthToken()
	if newAuthTokenErr != nil {
		return nil, newAuthTokenErr
	}
	logger.Log("GetCreds", "Successfully generated new auth token.")
	writeSpotifyAuthErr := writeSpotifyAuthtoken(*newAuthToken)
	if writeSpotifyAuthErr != nil {
		return nil, writeSpotifyAuthErr
	}
	logger.Log("GetCreds", "Successfully stored new auth token in DB.")
	return newAuthToken, nil
}
func fetchToken() (*firebase.FirestoreSpotifyAuthToken, error) {
	logger.Log("FetchToken", "Starting...")
	snapshot, snapshotErr := firestoreClient.Collection("internal_tokens").Doc("spotifyAuthToken").Get(context.Background())
	if status.Code(snapshotErr) == codes.NotFound {
		logger.Log("FetchToken", "SpotifyAuthToken not found in DB. Need to create.")
		return nil, nil
	}
	if snapshotErr != nil {
		return nil, fmt.Errorf(snapshotErr.Error())
	}
	logger.Log("FetchToken", "Successfully got snapshot.")
	var spotifyAuthToken firebase.FirestoreSpotifyAuthToken
	dataToErr := snapshot.DataTo(&spotifyAuthToken)
	if dataToErr != nil {
		return nil, fmt.Errorf(dataToErr.Error())
	}
	logger.Log("FetchToken", "Successfully decoded auth token.")
	return &spotifyAuthToken, nil
}
func generateAuthToken() (*firebase.FirestoreSpotifyAuthToken, error) {
	logger.Log("GenerateAuthToken", "Starting...")
	authStr := os.Getenv("SPOTIFY_CLIENTID") + ":" + os.Getenv("SPOTIFY_SECRET")
	data := url.Values{}
	data.Set("grant_type", "client_credentials")
	accessTokenReq, accessTokenReqErr := http.NewRequest("POST", spotifyAccessTokenURI,
		strings.NewReader(data.Encode()))
	if accessTokenReqErr != nil {
		return nil, fmt.Errorf(accessTokenReqErr.Error())
	}
	logger.Log("GenerateAuthToken", "Request generated.")
	accessTokenReq.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	accessTokenReq.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(authStr)))
	accessTokenResp, accessTokenRespErr := httpClient.Do(accessTokenReq)
	if accessTokenRespErr != nil {
		return nil, fmt.Errorf(accessTokenRespErr.Error())
	}
	logger.Log("GenerateAuthToken", "Response received.")
	var spotifyClientCredsAuthResp social.SpotifyClientCredsAuthResp
	refreshTokenDecodeErr := json.NewDecoder(accessTokenResp.Body).Decode(&spotifyClientCredsAuthResp)
	if refreshTokenDecodeErr != nil {
		return nil, fmt.Errorf(refreshTokenDecodeErr.Error())
	}
	logger.Log("GenerateAuthToken", "Successfully decoded token.")
	issuedAt := time.Now()
	expiresAt := issuedAt.Add(time.Second * time.Duration(spotifyClientCredsAuthResp.ExpiresIn))
	authToken := firebase.FirestoreSpotifyAuthToken{
		IssuedAt:  issuedAt.Format(time.RFC3339),
		ExpiresIn: spotifyClientCredsAuthResp.ExpiresIn,
		ExpiredAt: expiresAt.Format(time.RFC3339),
		Token:     spotifyClientCredsAuthResp.AccessToken,
	}
	logger.Log("GenerateAuthToken", "Successfully generated token to store in DB.")
	return &authToken, nil
}
func refreshAuthToken(authToken firebase.FirestoreSpotifyAuthToken) (*firebase.FirestoreSpotifyAuthToken, error) {
	logger.Log("RefreshAuthToken", "Starting...")
	var currentTime = time.Now()
	logger.Log("RefreshAuthToken", fmt.Sprintf("Expires In: %d seconds\n", authToken.ExpiresIn))
	logger.Log("RefreshAuthToken", fmt.Sprintf("Expires At: %s seconds\n", authToken.ExpiredAt))
	expiredAtTime, expiredAtTimeErr := time.Parse(time.RFC3339, authToken.ExpiredAt)
	if expiredAtTimeErr != nil {
		return nil, fmt.Errorf(expiredAtTimeErr.Error())
	}
	logger.Log("RefreshAuthToken", "Successfully parsed ExpiredAtTime.")
	if currentTime.After(expiredAtTime) {
		logger.Log("RefreshAuthToken", "SpotifyAuthToken is expired. Refreshing...")
		refreshToken, tokenActionErr := generateAuthToken()
		if tokenActionErr != nil {
			return nil, fmt.Errorf(tokenActionErr.Error())
		}
		logger.Log("RefreshAuthToken", "Successfully generated auth token.")
		writeTokenErr := writeSpotifyAuthtoken(*refreshToken)
		if writeTokenErr != nil {
			return nil, fmt.Errorf(writeTokenErr.Error())
		}
		logger.Log("RefreshAuthToken", "Successfully wrote token to Firestore")
		return refreshToken, nil
	}
	return &authToken, nil
}
func writeSpotifyAuthtoken(authToken firebase.FirestoreSpotifyAuthToken) error {
	logger.Log("WriteSpotifyAuthtoken", "Starting...")
	spotifyAuthTokenDoc := firestoreClient.Collection("internal_tokens").Doc("spotifyAuthToken")
	if spotifyAuthTokenDoc == nil {
		return fmt.Errorf("spotifyAuthTokenDoc could not be found")
	}
	logger.Log("WriteSpotifyAuthtoken", "Successfully received SpotifyAuthTokenDoc.")
	authMap := map[string]interface{}{
		"expiredAt": authToken.ExpiredAt,
		"expiresIn": authToken.ExpiresIn,
		"issuedAt":  authToken.IssuedAt,
		"token":     authToken.Token,
	}
	_, writeErr := spotifyAuthTokenDoc.Set(context.Background(), authMap, firestore.MergeAll)
	if writeErr != nil {
		return fmt.Errorf(writeErr.Error())
	}
	logger.Log("WriteSpotifyAuthtoken", "Successfully set token in Firestore.")
	return nil
}
func getSpotifyTrack(trackID string, accessToken string) (*firebase.FirestoreMedia, error) {
	logger.Log("GetSpotifyTrack", "Starting...")
	spotifyGetURI := spotifyGetTrackURI + "/" + trackID
	spotifyTrackReq, spotifyTrackReqErr := http.NewRequest("GET", spotifyGetURI, nil)
	if spotifyTrackReqErr != nil {
		return nil, fmt.Errorf("GetSpotifyMedia [http.NewRequest]: %v", spotifyTrackReqErr)
	}
	logger.Log("GetSpotifyTrack", "Generated track request.")
	spotifyTrackReq.Header.Add("Authorization", "Bearer "+accessToken)
	getTrackResp, spotifyTrackRespErr := httpClient.Do(spotifyTrackReq)
	if spotifyTrackRespErr != nil {
		return nil, fmt.Errorf("GetSpotifyMedia [client.Do]: %v", spotifyTrackRespErr)
	}
	logger.Log("GetSpotifyTrack", "Received track response.")
	if getTrackResp.StatusCode != http.StatusOK {
		logger.Log("GetSpotifyTrack", "Received error. Decoding...")
		var spotifyErrorObj social.SpotifyRequestError
		err := json.NewDecoder(getTrackResp.Body).Decode(&spotifyErrorObj)
		if err != nil {
			return nil, fmt.Errorf("GetSpotifyMedia [Spotify Request Decoder]: %v", err)
		}
		return nil, fmt.Errorf("GetSpotifyMedia [Spotify Track Request]: %v", spotifyErrorObj.Error.Message)
	}
	var spotifyTrackData spotifyTrackResp
	respDecodeErr := json.NewDecoder(getTrackResp.Body).Decode(&spotifyTrackData)
	if respDecodeErr != nil {
		return nil, fmt.Errorf("GetSpotifyMedia [Spotify Response Decoder]: %v", respDecodeErr)
	}
	logger.Log("GetSpotifyTrack", "Successfully decoded response data.")
	firestoreMedia := firebase.FirestoreMedia{
		Name:    spotifyTrackData.Name,
		Album:   spotifyTrackData.Album.Name,
		Type:    spotifyTrackData.Type,
		Creator: generateArtistsString(spotifyTrackData.Artists),
		Spotify: firebase.FirestoreMediaPlatformData{
			ID:     trackID,
			URL:    spotifyTrackData.ExternalURLs.Spotify,
			Images: spotifyTrackData.Album.Images,
		},
	}
	logger.Log("GetSpotifyTrack", "Successfully created firestore media object.")
	return &firestoreMedia, nil
}
func getSpotifyPlaylist(playlistID string, accessToken string) (*firebase.FirestoreMedia, error) {
	logger.Log("GetSpotifyPlaylist", "Starting...")
	spotifyGetURI := spotifyGetPlaylistURI + "/" + playlistID
	spotifyPlaylistReq, spotifyPlaylistReqErr := http.NewRequest("GET", spotifyGetURI, nil)
	if spotifyPlaylistReqErr != nil {
		return nil, fmt.Errorf("GetSpotifyMedia [http.NewRequest]: %v", spotifyPlaylistReqErr)
	}
	logger.Log("GetSpotifyPlaylist", "Generated playlist request.")
	spotifyPlaylistReq.Header.Add("Authorization", "Bearer "+accessToken)
	getPlaylistResp, spotifyPlaylistRespErr := httpClient.Do(spotifyPlaylistReq)
	if spotifyPlaylistRespErr != nil {
		return nil, fmt.Errorf("GetSpotifyMedia [client.Do]: %v", spotifyPlaylistRespErr)
	}
	logger.Log("GetSpotifyPlaylist", "Received playlist response.")
	if getPlaylistResp.StatusCode != http.StatusOK {
		logger.Log("GetSpotifyPlaylist", "Received error. Decoding...")
		var spotifyErrorObj social.SpotifyRequestError
		err := json.NewDecoder(getPlaylistResp.Body).Decode(&spotifyErrorObj)
		if err != nil {
			return nil, fmt.Errorf("GetSpotifyMedia [Spotify Request Decoder]: %v", err)
		}
		return nil, fmt.Errorf("GetSpotifyMedia [Spotify Track Request]: %v", spotifyErrorObj.Error.Message)
	}
	var playlistData spotifyPlaylistResp
	respDecodeErr := json.NewDecoder(getPlaylistResp.Body).Decode(&playlistData)
	if respDecodeErr != nil {
		return nil, fmt.Errorf("GetSpotifyMedia [Spotify Response Decoder]: %v", respDecodeErr)
	}
	logger.Log("GetSpotifyPlaylist", "Successfully decoded response.")
	firestoreMedia := firebase.FirestoreMedia{
		Name:    playlistData.Name,
		Album:   "Playlist",
		Type:    "playlist",
		Creator: playlistData.Owner.DisplayName,
		Spotify: firebase.FirestoreMediaPlatformData{
			ID:     playlistData.ID,
			URL:    playlistData.ExternalURLs.Spotify,
			Images: playlistData.Images,
		},
	}
	logger.Log("GetSpotifyPlaylist", "Successfully created firestore media object.")
	return &firestoreMedia, nil
}
func getSpotifyAlbum(albumID string, accessToken string) (*firebase.FirestoreMedia, error) {
	logger.Log("GetSpotifyAlbum", "Starting...")
	spotifyGetURI := spotifyGetAlbumURI + "/" + albumID
	spotifyAlbumReq, spotifyAlbumReqErr := http.NewRequest("GET", spotifyGetURI, nil)
	if spotifyAlbumReqErr != nil {
		return nil, fmt.Errorf("GetSpotifyMedia [http.NewRequest]: %v", spotifyAlbumReqErr)
	}
	logger.Log("GetSpotifyAlbum", "Generated album request.")
	spotifyAlbumReq.Header.Add("Authorization", "Bearer "+accessToken)
	spotifyAlbumResp, spotifyAlbumRespErr := httpClient.Do(spotifyAlbumReq)
	if spotifyAlbumRespErr != nil {
		return nil, fmt.Errorf("GetSpotifyMedia [client.Do]: %v", spotifyAlbumRespErr)
	}
	logger.Log("GetSpotifyAlbum", "Received album response.")
	if spotifyAlbumResp.StatusCode != http.StatusOK {
		logger.Log("GetSpotifyAlbum", "Received error. Decoding...")
		var spotifyErrorObj social.SpotifyRequestError
		err := json.NewDecoder(spotifyAlbumResp.Body).Decode(&spotifyErrorObj)
		if err != nil {
			return nil, fmt.Errorf("GetSpotifyMedia [Spotify Request Decoder]: %v", err)
		}
		return nil, fmt.Errorf("GetSpotifyMedia [Spotify Track Request]: %v", spotifyErrorObj.Error.Message)
	}
	var albumData spotifyAlbum
	respDecodeErr := json.NewDecoder(spotifyAlbumResp.Body).Decode(&albumData)
	if respDecodeErr != nil {
		return nil, fmt.Errorf("GetSpotifyMedia [Spotify Response Decoder]: %v", respDecodeErr)
	}
	logger.Log("GetSpotifyAlbum", "Successfully decoded album data.")
	firestoreMedia := firebase.FirestoreMedia{
		Name:    albumData.Name,
		Album:   albumData.Name,
		Type:    albumData.Type,
		Creator: generateArtistsString(albumData.Artists),
		Spotify: firebase.FirestoreMediaPlatformData{
			ID:     albumData.ID,
			URL:    albumData.ExternalURLs.Spotify,
			Images: albumData.Images,
		},
	}
	logger.Log("GetSpotifyAlbum", "Successfully created firestore media object.")
	return &firestoreMedia, nil
}