package spotify

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/sirupsen/logrus"
	"golang.org/x/oauth2"
)

func getCurrentTrackForChannel(channel string) (track currentPlayingTrackResponse, err error) {
	channel = strings.TrimLeft(channel, "#")

	conf, err := oauthConfig(channel, "")
	if err != nil {
		return track, fmt.Errorf("getting oauth config: %w", err)
	}

	var token *oauth2.Token
	if err = db.ReadEncryptedCoreMeta(strings.Join([]string{"spotify-auth", channel}, ":"), &token); err != nil {
		return track, fmt.Errorf("loading oauth token: %w", err)
	}

	defer func() {
		if err := db.StoreEncryptedCoreMeta(strings.Join([]string{"spotify-auth", channel}, ":"), token); err != nil {
			logrus.WithError(err).Error("storing back Spotify auth token")
		}
	}()

	ctx, cancel := context.WithTimeout(context.Background(), spotifyRequestTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.spotify.com/v1/me/player/currently-playing", nil)
	if err != nil {
		return track, fmt.Errorf("creating currently-playing request: %w", err)
	}

	resp, err := conf.Client(context.Background(), token).Do(req)
	if err != nil {
		return track, fmt.Errorf("executing request: %w", err)
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			logrus.WithError(err).Error("closing Spotify response body (leaked fd)")
		}
	}()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return track, fmt.Errorf("reading response body: %w", err)
	}

	switch resp.StatusCode {
	case http.StatusOK:
		// This is perfect, continue below

	case http.StatusUnauthorized:
		// The token is FUBAR
		return track, fmt.Errorf("token expired (HTTP 401 - unauthorized)")

	case http.StatusForbidden:
		// The request is FUBAR
		return track, fmt.Errorf("bad oAuth request, report this to dev (HTTP 403 - forbidden): %q", body)

	case http.StatusTooManyRequests:
		// We asked too often
		return track, fmt.Errorf("rate-limited (HTTP 429 - too many requests)")

	default:
		// WTF?
		return track, fmt.Errorf("unexpected HTTP status %d", resp.StatusCode)
	}

	if err = json.Unmarshal(body, &track); err != nil {
		return track, fmt.Errorf("decoding response (%q): %w", body, err)
	}

	return track, nil
}

func getCurrentArtistTitleForChannel(channel string) (artistTitle string, err error) {
	track, err := getCurrentTrackForChannel(channel)
	if err != nil {
		return "", fmt.Errorf("getting track info: %w", err)
	}

	var artistNames []string
	for _, artist := range track.Item.Artists {
		artistNames = append(artistNames, artist.Name)
	}

	return strings.Join([]string{
		strings.Join(artistNames, ", "),
		track.Item.Name,
	}, " - "), nil
}

func getCurrentLinkForChannel(channel string) (link string, err error) {
	track, err := getCurrentTrackForChannel(channel)
	if err != nil {
		return "", fmt.Errorf("getting track info: %w", err)
	}

	return track.Item.ExternalUrls.Spotify, nil
}