package models

import (
	"encoding/xml"
	"errors"
	"fmt"
	"net/url"
)

// Error constants for speaker validation
var (
	ErrInvalidURL     = errors.New("URL cannot be empty")
	ErrInvalidAppKey  = errors.New("app key cannot be empty")
	ErrInvalidService = errors.New("service cannot be empty")
	ErrInvalidVolume  = errors.New("volume must be between 0 and 100")
)

// PlayInfo represents the request body for the /speaker endpoint to play TTS or URL content
type PlayInfo struct {
	XMLName xml.Name `xml:"play_info"`
	URL     string   `xml:"url"`
	AppKey  string   `xml:"app_key"`
	Service string   `xml:"service"`
	Message string   `xml:"message"`
	Reason  string   `xml:"reason"`
	Volume  *int     `xml:"volume,omitempty"`
}

// SpeakerResponse represents the response from the /speaker endpoint
type SpeakerResponse struct {
	XMLName xml.Name `xml:"status"`
	Value   string   `xml:",chardata"`
}

// SpeakerPlayStatus represents the status during speaker playback
type SpeakerPlayStatus struct {
	Service string `json:"service"`
	Message string `json:"message"`
	Reason  string `json:"reason"`
	Volume  int    `json:"volume,omitempty"`
}

// NewPlayInfo creates a new PlayInfo instance for TTS or URL playback
func NewPlayInfo(url, appKey, service, message, reason string) *PlayInfo {
	return &PlayInfo{
		XMLName: xml.Name{Local: "play_info"},
		URL:     url,
		AppKey:  appKey,
		Service: service,
		Message: message,
		Reason:  reason,
	}
}

// SetVolume sets the volume level for playback
func (p *PlayInfo) SetVolume(volume int) *PlayInfo {
	p.Volume = &volume
	return p
}

// BuildTranslateTTSURL builds the (undocumented) Google Translate TTS URL the
// speaker fetches directly for a /speaker notification. language is a short code
// such as "EN" or "DE". Shared by NewTTSPlayInfo and the TTS service's Translate
// provider so the query-string format lives in exactly one place.
//
// https://translate.google.com/translate_tts?ie=UTF-8&tl=de&client=aftertouch&q=Hallo+Wie+Geht%27s
func BuildTranslateTTSURL(text, language string) string {
	return fmt.Sprintf("https://translate.google.com/translate_tts?ie=UTF-8&tl=%s&client=tw-ob&q=%s", language, url.QueryEscape(text))
}

// NewTTSPlayInfo creates a PlayInfo for Google TTS playback
func NewTTSPlayInfo(text, appKey, language string, volume ...int) *PlayInfo {
	// URL encode the text for Google TTS
	ttsURL := BuildTranslateTTSURL(text, language)

	playInfo := &PlayInfo{
		XMLName: xml.Name{Local: "play_info"},
		URL:     ttsURL,
		AppKey:  appKey,
		Service: "TTS Notification",
		Message: "Google TTS",
		Reason:  text,
	}

	if len(volume) > 0 {
		playInfo.Volume = &volume[0]
	}

	return playInfo
}

// NewURLPlayInfo creates a PlayInfo for URL content playback
func NewURLPlayInfo(url, appKey, service, message, reason string, volume ...int) *PlayInfo {
	playInfo := &PlayInfo{
		XMLName: xml.Name{Local: "play_info"},
		URL:     url,
		AppKey:  appKey,
		Service: service,
		Message: message,
		Reason:  reason,
	}

	if len(volume) > 0 {
		playInfo.Volume = &volume[0]
	}

	return playInfo
}

// Validate validates the PlayInfo request
func (p *PlayInfo) Validate() error {
	if p.URL == "" {
		return ErrInvalidURL
	}

	if p.AppKey == "" {
		return ErrInvalidAppKey
	}

	if p.Service == "" {
		return ErrInvalidService
	}

	if p.Volume != nil && (*p.Volume < 0 || *p.Volume > 100) {
		return ErrInvalidVolume
	}

	return nil
}

// String returns a string representation of the PlayInfo
func (p *PlayInfo) String() string {
	volumeStr := "current"
	if p.Volume != nil {
		volumeStr = string(rune(*p.Volume))
	}

	return "Service: " + p.Service + ", Message: " + p.Message + ", Volume: " + volumeStr
}
