package tmi

import (
	"time"

	zumaapi "code.justin.tv/chat/zuma/app/api"
)

type JSONChatRoomUpdatedMessage struct {
	Room JSONChatRoom `json:"room"`
}

type JSONChatRoom struct {
	ID    string        `json:"channel_id"`
	Modes JSONRoomModes `json:"modes"`
	// Rules is a list of rules to display to users when joining a chat channel.
	Rules []string `json:"rules"`
}

type JSONRoomModes struct {
	// FollowersOnlyDurationMinutes is the number of minutes a user must be following the broadcaster in order to chat If value is null, followers only mode is not enabled.
	FollowersOnlyDurationMinutes *int `json:"followers_only_duration_minutes"`
	// EmoteOnlyModeEnabled indicates if the broadcaster requires chat messages to consist only of emotes
	EmoteOnlyModeEnabled bool `json:"emote_only_mode_enabled"`
	// R9KModeEnabled indicates if the broadcaster requires chat messages to be unique
	R9KModeEnabled bool `json:"r9k_mode_enabled"`
	// SubscribersOnlyModeEnabled indicates whether chat is currently restricted to subscribers only.
	SubscribersOnlyModeEnabled bool `json:"subscribers_only_mode_enabled"`
	// VerifiedOnlyModeEnabled indicates if users must be verified to chat.
	VerifiedOnlyModeEnabled bool `json:"verified_only_mode_enabled"`
	// SlowModeDurationSeconds is the number of seconds a user must wait in between sending chat messages If value is null, slow mode is not enabled.
	SlowModeDurationSeconds *int `json:"slow_mode_duration_seconds"`
	// SlowModeSetAt is the time that slowmode was turned on (if slowmode is enabled)
	SlowModeSetAt time.Time `json:"slow_mode_set_at"`
}

type JSONMessageContent struct {
	Text      string                       `json:"text" validate:"nonzero"`
	Fragments []JSONMessageContentFragment `json:"fragments,omitempty"`
}

type JSONMessageContentFragment struct {
	Text string `json:"text" validate:"nonzero"`

	Emoticon *JSONMessageContentFragmentEmoticon `json:"emoticon,omitempty"`
	Link     *JSONMessageContentFragmentLink     `json:"link,omitempty"`
	Mention  *JSONMessageContentFragmentMention  `json:"mention,omitempty"`
}

type JSONMessageContentFragmentEmoticon struct {
	EmoticonID    string `json:"id" validate:"nonzero"`
	EmoticonSetID string `json:"set_id" validate:"nonzero"`
}

type JSONMessageContentFragmentLink struct {
	Host          string                               `json:"host" validate:"nonzero"`
	EmbedMetadata *JSONMessageContentFragmentLinkEmbed `json:"embed_metadata,omitempty"`
}

type JSONMessageContentFragmentLinkEmbed struct {
	ErrorCode    string `json:"error_code,omitempty"`
	RequestURL   string `json:"request_url"`
	Type         string `json:"type"`
	Title        string `json:"title"`
	Description  string `json:"description"`
	AuthorName   string `json:"author_name,omitempty"`
	AuthorURL    string `json:"author_url,omitempty"`
	ThumbnailURL string `json:"thumbnail_url"`
	ProviderName string `json:"provider_name"`

	TwitchMetadata *JSONEmbedTwitchMetadata `json:"twitch_metadata,omitempty"`
}

type JSONEmbedTwitchMetadata struct {
	TwitchType string `json:"twitch_type"`

	Clip   *JSONTwitchEmbedClip   `json:"clip,omitempty"`
	VOD    *JSONTwitchEmbedVOD    `json:"vod,omitempty"`
	Stream *JSONTwitchEmbedStream `json:"stream,omitempty"`
	Event  *JSONTwitchEmbedEvent  `json:"event,omitempty"`
}

type JSONTwitchEmbedClip struct {
	BroadcasterID      string     `json:"broadcaster_id"`
	BroadcasterLogin   string     `json:"broadcaster_login"`
	CreatedAt          *time.Time `json:"created_at"`
	Game               string     `json:"game"`
	Slug               string     `json:"slug"`
	VideoLengthSeconds int        `json:"video_length"`
	ViewCount          int        `json:"view_count"`
}

type JSONTwitchEmbedVOD struct {
	BroadcasterID      string     `json:"broadcaster_id"`
	BroadcasterLogin   string     `json:"broadcaster_login"`
	CreatedAt          *time.Time `json:"created_at"`
	Game               string     `json:"game"`
	VideoLengthSeconds int        `json:"video_length"`
	ViewCount          int        `json:"view_count"`
}

type JSONTwitchEmbedStream struct {
	BroadcasterID    string     `json:"broadcaster_id"`
	BroadcasterLogin string     `json:"broadcaster_login"`
	CreatedAt        *time.Time `json:"created_at"`
	Game             string     `json:"game"`
	StreamType       string     `json:"stream_type"`
	ViewCount        int        `json:"view_count"`
}

type JSONTwitchEmbedEvent struct {
	AuthorID    string     `json:"author_id"`
	AuthorLogin string     `json:"author_login"`
	Game        string     `json:"game"`
	StartTime   *time.Time `json:"start_time"`
	EndTime     *time.Time `json:"end_time"`
}

type JSONMessageContentFragmentMention struct {
	UserID      string `json:"user_id" validate:"nonzero"`
	Login       string `json:"login" validate:"nonzero"`
	DisplayName string `json:"display_name" validate:"nonzero"`
}

type JSONUserBadge struct {
	ID      string `json:"id" validate:"nonzero"`
	Version string `json:"version" validate:"nonzero"`
}

func BuildMessageContent(m zumaapi.MessageContentV2) JSONMessageContent {
	fragments := []JSONMessageContentFragment{}
	for _, f := range m.Fragments {
		var emoticonFragment *JSONMessageContentFragmentEmoticon
		if f.Emoticon != nil {
			emoticonFragment = &JSONMessageContentFragmentEmoticon{
				EmoticonID:    f.Emoticon.EmoticonID,
				EmoticonSetID: f.Emoticon.EmoticonSetID,
			}
		}

		var linkFragment *JSONMessageContentFragmentLink
		if f.Link != nil {
			var em *JSONMessageContentFragmentLinkEmbed
			if embedMetadata := f.Link.EmbedMetadata; embedMetadata != nil {
				em = exportJSONMessageEmbed(embedMetadata)
			}
			linkFragment = &JSONMessageContentFragmentLink{
				Host:          f.Link.Host,
				EmbedMetadata: em,
			}
		}

		var mentionFragment *JSONMessageContentFragmentMention
		if f.Mention != nil {
			mentionFragment = &JSONMessageContentFragmentMention{
				UserID:      f.Mention.UserID,
				Login:       f.Mention.Login,
				DisplayName: f.Mention.DisplayName,
			}
		}

		fragments = append(fragments, JSONMessageContentFragment{
			Text:     f.Text,
			Emoticon: emoticonFragment,
			Link:     linkFragment,
			Mention:  mentionFragment,
		})
	}

	return JSONMessageContent{
		Text:      m.Text,
		Fragments: fragments,
	}
}

func exportJSONMessageEmbed(e *zumaapi.MessageContentFragmentLinkEmbed) *JSONMessageContentFragmentLinkEmbed {
	if e == nil {
		return nil
	}

	JSONEmbed := &JSONMessageContentFragmentLinkEmbed{
		ErrorCode:    e.ErrorCode,
		RequestURL:   e.RequestURL,
		Type:         e.Type,
		Title:        e.Title,
		Description:  e.Description,
		AuthorName:   e.AuthorName,
		AuthorURL:    e.AuthorURL,
		ThumbnailURL: e.ThumbnailURL,
		ProviderName: e.ProviderName,
	}

	if md := e.TwitchMetadata; md != nil {
		twitchMetadata := &JSONEmbedTwitchMetadata{TwitchType: md.TwitchType}
		if md.Clip != nil {
			twitchMetadata.Clip = (*JSONTwitchEmbedClip)(md.Clip)
		} else if md.VOD != nil {
			twitchMetadata.VOD = (*JSONTwitchEmbedVOD)(md.VOD)
		} else if md.Stream != nil {
			twitchMetadata.Stream = (*JSONTwitchEmbedStream)(md.Stream)
		} else if md.Event != nil {
			twitchMetadata.Event = (*JSONTwitchEmbedEvent)(md.Event)
		}

		JSONEmbed.TwitchMetadata = twitchMetadata
	}

	return JSONEmbed
}
