package youtube

import (
	"testing"

	"github.com/stretchr/testify/assert"

	"google.golang.org/api/youtube/v3"
)

type mockClient struct {
	ValidVideoIds  []string
	UpdatedChannel *youtube.Channel
	OldChannel     *youtube.Channel
}

func (yt *mockClient) ListChannels() (*youtube.ChannelListResponse, error) {
	return &youtube.ChannelListResponse{
		Items: []*youtube.Channel{
			yt.OldChannel,
		},
	}, nil
}

func (yt *mockClient) UpdateChannel(updatedChannel *youtube.Channel) error {
	yt.UpdatedChannel = updatedChannel
	return nil
}

func (yt *mockClient) VideoExists(id string) (bool, error) {
	for _, validID := range yt.ValidVideoIds {
		if id == validID {
			return true, nil
		}
	}
	return false, nil
}

func TestCleanPromotionsRemovesTwitchAnnotation(t *testing.T) {
	client := &mockClient{}
	promotions := &youtube.InvideoPromotion{
		Items: []*youtube.PromotedItem{
			{
				Id: &youtube.PromotedItemId{
					Type:       "website",
					WebsiteUrl: "https://www.twitch.tv/yt/asdf",
				},
			},
			{
				Id: &youtube.PromotedItemId{
					Type:       "website",
					WebsiteUrl: "https://not.twitch.tv",
				},
			},
		},
	}

	cleanedPromotions, err := cleanPromotionItems(client, promotions)

	assert.Nil(t, err)
	assert.Equal(t, 1, len(cleanedPromotions))
	assert.Equal(t, "https://not.twitch.tv", cleanedPromotions[0].Id.WebsiteUrl)
}

func TestCleanPromotionsRemovesInvalidVideo(t *testing.T) {
	client := &mockClient{
		ValidVideoIds: []string{"123"},
	}
	promotions := &youtube.InvideoPromotion{
		Items: []*youtube.PromotedItem{
			{
				Id: &youtube.PromotedItemId{
					Type:    "video",
					VideoId: "123",
				},
			},
			{
				Id: &youtube.PromotedItemId{
					Type:    "video",
					VideoId: "456",
				},
			},
		},
	}

	cleanedPromotions, err := cleanPromotionItems(client, promotions)

	assert.Nil(t, err)
	assert.Equal(t, 1, len(cleanedPromotions))
	assert.Equal(t, "123", cleanedPromotions[0].Id.VideoId)
}

func TestSetAnnotationsDownNoPromotions(t *testing.T) {
	old := &youtube.Channel{}
	client := &mockClient{
		OldChannel: old,
	}

	err := setYoutubeAnnotationsStatus(client, "asdf", StatusDown)

	assert.Nil(t, err)
	assert.Nil(t, client.UpdatedChannel, "should return without making a call")
}

func TestSetAnnotationsDown(t *testing.T) {
	old := &youtube.Channel{
		InvideoPromotion: &youtube.InvideoPromotion{
			Items: []*youtube.PromotedItem{
				{
					Id: &youtube.PromotedItemId{
						Type:       "website",
						WebsiteUrl: "https://www.twitch.tv/yt/asdf",
					},
				},
			},
		},
	}
	client := &mockClient{
		OldChannel: old,
	}

	err := setYoutubeAnnotationsStatus(client, "asdf", StatusDown)

	assert.Nil(t, err)
	assert.Equal(t, 0, len(client.UpdatedChannel.InvideoPromotion.Items))
}

func TestSetAnnotationsUp(t *testing.T) {
	old := &youtube.Channel{}
	client := &mockClient{
		OldChannel: old,
	}

	err := setYoutubeAnnotationsStatus(client, "userid", StatusUp)

	assert.Nil(t, err)
	assert.Equal(t, 1, len(client.UpdatedChannel.InvideoPromotion.Items))
	assert.Equal(t, "https://www.twitch.tv/yt/userid", client.UpdatedChannel.InvideoPromotion.Items[0].Id.WebsiteUrl)
}

func TestClearAnnotations(t *testing.T) {
	old := &youtube.Channel{}
	client := &mockClient{
		OldChannel: old,
	}

	err := clearYoutubeAnnotations(client, "userid")

	assert.Nil(t, err)
	assert.Equal(t, 0, len(client.UpdatedChannel.InvideoPromotion.Items))
}

func TestGetAnnotations(t *testing.T) {
	old := &youtube.Channel{
		InvideoPromotion: &youtube.InvideoPromotion{
			Items: []*youtube.PromotedItem{
				{
					Id: &youtube.PromotedItemId{
						Type:       "website",
						WebsiteUrl: "https://www.twitch.tv/yt/asdf",
					},
				},
			},
		},
	}
	client := &mockClient{
		OldChannel: old,
	}

	res, err := getYoutubeAnnotations(client, "userid")

	assert.Nil(t, err)
	assert.Equal(t, 1, len(res.Items))
}
