package models

import (
	"fmt"
	"time"

	"code.justin.tv/common/yimg"
)

type ChannelPropertiesResult struct {
	Results        []ChannelProperties `json:"results"`
	BadIdentifiers []ErrBadIdentifier  `json:"bad_identifiers"`
}

type ChannelProperties struct {
	ID                  uint64     `json:"id"`
	Name                string     `json:"name"`
	DirectoryHidden     bool       `json:"directory_hidden"`
	Broadcaster         *string    `json:"broadcaster"`
	BroadcasterLanguage *string    `json:"broadcaster_language"`
	BroadcasterSoftware *string    `json:"broadcaster_software"`
	CreatedOn           *time.Time `json:"created_on"`
	Game                *string    `json:"game"`
	GameID              *uint64    `json:"game_id"`
	Mature              *bool      `json:"mature"`
	Status              *string    `json:"status"`
	Title               *string    `json:"title"`
	UpdatedOn           *time.Time `json:"updated_on"`
	ViewsCount          *uint64    `json:"views_count"`

	LastBroadcastTime        *time.Time `json:"last_broadcast_time"`
	LastBroadcastID          *string    `json:"last_broadcast_id"`
	LastLiveNotificationSent *time.Time `json:"last_live_notification_sent"`

	About                   *string `json:"about"`
	RedirectChannel         *string `json:"redirect_channel"`
	PrimaryTeamID           *uint64 `json:"primary_team_id"`
	DisableChat             *bool   `json:"disable_chat"`

	ChannelOfflineImage          yimg.Images `json:"channel_offline_image"`
	ProfileBanner                yimg.Images `json:"profile_banner"`
	ProfileBannerBackgroundColor *string     `json:"profile_banner_background_color"`

	DmcaViolation           *bool      `json:"dmca_violation" `
	TermsOfServiceViolation *bool      `json:"terms_of_service_violation" `
	DeletedOn               *time.Time `json:"deleted_on" `
	UsernameFlaggedOn       *time.Time `json:"username_flagged_on" `

	PrivateVideo          *bool `json:"private_video"`
	PrivacyOptionsEnabled *bool `json:"privacy_options_enabled"`
}

type UpdateChannelProperties struct {
	RemoteIp            *string    `json:"remote_ip,omitempty"`
	ID                  uint64     `json:"id,omitempty" validate:"nonzero"`
	Login               *string    `json:"login,omitempty"`
	DirectoryHidden     *bool      `json:"directory_hidden,omitempty"`
	Broadcaster         *string    `json:"broadcaster,omitempty"`
	BroadcasterLanguage *string    `json:"broadcaster_language,omitempty"`
	BroadcasterSoftware *string    `json:"broadcaster_software,omitempty"`
	Game                *string    `json:"game,omitempty"`
	GameID              *uint64    `json:"game_id,omitempty"`
	Mature              *bool      `json:"mature,omitempty"`
	Status              *string    `json:"status,omitempty"`
	Title               *string    `json:"title,omitempty"`
	UpdatedOn           *time.Time `json:"updated_on,omitempty"`
	ViewsCount          *uint64    `json:"views_count,omitempty"`

	LastBroadcastTime        *time.Time `json:"last_broadcast_time,omitempty"`
	LastBroadcastID          *string    `json:"last_broadcast_id,omitempty"`
	LastLiveNotificationSent *time.Time `json:"last_live_notification_sent,omitempty"`

	About                   *string `json:"about,omitempty"`
	RedirectChannel         *string `json:"redirect_channel,omitempty"`
	DisableChat             *bool   `json:"disable_chat,omitempty"`

	PrimaryTeamID       *uint64 `json:"primary_team_id,omitempty"`
	DeletePrimaryTeamID bool    `json:"delete_primary_team_id,omitempty"`

	ClientID string `json:"client_id,omitempty"`

	PrivacyOptionsEnabled *bool `json:"privacy_options_enabled"`
	PrivateVideo          *bool `json:"private_video"`

	Service string `json:"service"`
}

const (
	ServiceBlender = "blender"
)

func (up *UpdateChannelProperties) FillFromProperties(p *ChannelProperties) *UpdateChannelProperties {
	uup := &UpdateChannelProperties{
		ID:                  up.ID,
		DirectoryHidden:     up.DirectoryHidden,
		Broadcaster:         up.Broadcaster,
		BroadcasterLanguage: up.BroadcasterLanguage,
		BroadcasterSoftware: up.BroadcasterSoftware,
		Game:                up.Game,
		GameID:              up.GameID,
		Mature:              up.Mature,
		Status:              up.Status,
		Title:               up.Title,
		UpdatedOn:           up.UpdatedOn,
		ViewsCount:          up.ViewsCount,

		LastBroadcastTime:        up.LastBroadcastTime,
		LastBroadcastID:          up.LastBroadcastID,
		LastLiveNotificationSent: up.LastLiveNotificationSent,

		About:                   up.About,
		RedirectChannel:         up.RedirectChannel,
		DisableChat:             up.DisableChat,

		PrimaryTeamID:       up.PrimaryTeamID,
		DeletePrimaryTeamID: up.DeletePrimaryTeamID,

		PrivacyOptionsEnabled: up.PrivacyOptionsEnabled,
		PrivateVideo:          up.PrivateVideo,
	}

	defaultBool := false
	if uup.DirectoryHidden == nil {
		uup.DirectoryHidden = &p.DirectoryHidden
	}

	if uup.Broadcaster == nil {
		uup.Broadcaster = p.Broadcaster
	}

	if uup.BroadcasterLanguage == nil || *uup.BroadcasterLanguage == "" {
		if p.BroadcasterLanguage != nil {
			uup.BroadcasterLanguage = p.BroadcasterLanguage
		} else {
			defaultLang := "en"
			uup.BroadcasterLanguage = &defaultLang
		}
	}

	if uup.BroadcasterSoftware == nil {
		uup.BroadcasterSoftware = p.BroadcasterSoftware
	}

	if uup.Game == nil {
		uup.Game = p.Game
	}

	if uup.GameID == nil {
		uup.GameID = p.GameID
	}

	if uup.Mature == nil {
		uup.Mature = p.Mature
	}

	if uup.Status == nil {
		uup.Status = p.Status
	}

	if uup.Title == nil {
		uup.Title = p.Title
	}

	if uup.ViewsCount == nil {
		uup.ViewsCount = p.ViewsCount
	}

	if uup.LastBroadcastTime == nil {
		uup.LastBroadcastTime = p.LastBroadcastTime
	}

	if uup.LastBroadcastID == nil {
		uup.LastBroadcastID = p.LastBroadcastID
	}

	if uup.LastLiveNotificationSent == nil {
		uup.LastLiveNotificationSent = p.LastLiveNotificationSent
	}

	if uup.About == nil {
		uup.About = p.About
	}

	if uup.RedirectChannel == nil {
		uup.RedirectChannel = p.RedirectChannel
	}

	if uup.PrimaryTeamID == nil && !uup.DeletePrimaryTeamID {
		uup.PrimaryTeamID = p.PrimaryTeamID
	}

	if uup.DisableChat == nil {
		if p.DisableChat == nil {
			uup.DisableChat = &defaultBool
		} else {
			uup.DisableChat = p.DisableChat
		}
	}

	if uup.PrivacyOptionsEnabled == nil {
		uup.PrivacyOptionsEnabled = p.PrivacyOptionsEnabled
	}

	// We default this field to false, since PrivacyOptionsEnabled is a prerequisite.
	if uup.PrivateVideo == nil {
		if p.PrivateVideo == nil {
			uup.PrivateVideo = &defaultBool
		} else {
			uup.PrivateVideo = p.PrivateVideo
		}
	}

	return uup
}

func (up *UpdateChannelProperties) IsChannelUserPropertiesUpdate(cp *ChannelProperties) bool {
	return !isEqualString(up.About, cp.About) ||
		!isEqualString(up.RedirectChannel, cp.RedirectChannel) ||
		!isEqualUint64(up.PrimaryTeamID, cp.PrimaryTeamID) ||
		!isEqualBool(up.DisableChat, cp.DisableChat)
}

func (up *UpdateChannelProperties) IsChannelBroadcastPropertiesUpdate(p *ChannelProperties) bool {
	return !isEqualTime(up.LastBroadcastTime, p.LastBroadcastTime) ||
		!isEqualString(up.LastBroadcastID, p.LastBroadcastID) ||
		!isEqualTime(up.LastLiveNotificationSent, p.LastLiveNotificationSent)
}

func (up *UpdateChannelProperties) IsChannelVideoPrivacyPropertiesUpdate(p *ChannelProperties) bool {
	return !isEqualBool(up.PrivateVideo, p.PrivateVideo) ||
		!isEqualBool(up.PrivacyOptionsEnabled, p.PrivacyOptionsEnabled)
}
func (up *UpdateChannelProperties) IsChannelBasicPropertiesUpdate(p *ChannelProperties) bool {
	return (up.DirectoryHidden != nil && *up.DirectoryHidden != p.DirectoryHidden) ||
		!isEqualString(up.Broadcaster, p.Broadcaster) ||
		!isEqualString(up.BroadcasterLanguage, p.BroadcasterLanguage) ||
		!isEqualString(up.BroadcasterSoftware, p.BroadcasterSoftware) ||
		!isEqualString(up.Status, p.Status) ||
		!isEqualString(up.Title, p.Title) ||
		!isEqualString(up.Game, p.Game) ||
		!isEqualUint64(up.GameID, p.GameID) ||
		!isEqualUint64(up.ViewsCount, p.ViewsCount) ||
		!isEqualBool(up.Mature, p.Mature)
}

const (
	ChannelsIDCacheKey    = "u.id"
	ChannelsLoginCacheKey = "login"
)

func ChannelIDToString(id uint64) string {
	return fmt.Sprintf("%d", id)
}

func (p ChannelProperties) CachePairs() []CachePair {
	var pairs []CachePair

	if p.ID != 0 {
		pairs = append(pairs, CachePair{
			Key:   ChannelsIDCacheKey,
			Value: ChannelIDToString(p.ID),
		})
	}

	if p.Name != "" {
		pairs = append(pairs, CachePair{
			Key:   ChannelsLoginCacheKey,
			Value: p.Name,
		})
	}

	return pairs
}

func (p ChannelProperties) HasTosViolation() bool {
	return p.TermsOfServiceViolation != nil && *p.TermsOfServiceViolation
}

func (p ChannelProperties) HasDmcaViolation() bool {
	return p.DmcaViolation != nil && *p.DmcaViolation
}

type ChannelPropertiesIterator []ChannelProperties

func (i ChannelPropertiesIterator) Each(f func(Cacheable) error) error {
	for _, prop := range i {
		if err := f(prop); err != nil {
			return err
		}
	}

	return nil
}
