package main

import (
	"fmt"
	alexa "github.com/mikeflynn/go-alexa/skillserver"
	"github.com/mmcdole/gofeed"
	"strconv"
	"sync"
	"time"
)

const (
	FEEDURL = "https://www.heise.de/newsticker/heise-top-atom.xml"
	// Echo App ID from Amazon Dashboard
	APPID = "amzn1.ask.skill.08495b00-b382-4982-b50c-c31f4838b51d"
)

var feedCache FeedCache

// Hauptprogramm. Startet den Download des RSS-Feeds und initialisiert
// den HTTP-Handler.
func main() {
	fmt.Println("Erstmaliger Download des Newsfeeds")
	fp := gofeed.NewParser()
	feed, err := fp.ParseURL(FEEDURL)
	if err != nil || len(feed.Items) == 0 {
		panic("Konnte Feed nicht abrufen - Abbruch.")
	}
	feedCache.Set(feed)
	ticker := time.NewTicker(15 * time.Minute)
	quit := make(chan struct{})
	go func() {
		for {
			select {
			case <-ticker.C:
				fmt.Println("Update des Newsfeeds")
				newfeed, err := fp.ParseURL(FEEDURL)
				if err != nil {
					fmt.Println("Konnte Newsfeed nicht updaten: ", err.Error())
				} else {
					feedCache.Set(newfeed)
				}
			case <-quit:
				ticker.Stop()
				return
			}
		}
	}()
	defer close(quit)

	var Applications = map[string]interface{}{
		"/echo/heisetopnews": alexa.EchoApplication{ // Route
			AppID:    APPID,
			OnIntent: HeiseTopNewsHandler,
			OnLaunch: HeiseTopNewsHandler,
		},
	}

	alexa.Run(Applications, "3000")
}

// Handler für unseren Newsdienst. Dieser Code wird einmal pro Anfrage
// ausgeführt.
func HeiseTopNewsHandler(echoReq *alexa.EchoRequest,
	echoResp *alexa.EchoResponse) {
	intentname := echoReq.Request.Intent.Name
	fmt.Printf("----> Request für Intent %s empfangen\n", intentname)
	newsCount := 3 // Default value
	if intentname == "GetHeiseNumNews" {
		echoslot := echoReq.Request.Intent.Slots["Anzahl"]
		var err error
		if newsCount, err = strconv.Atoi(echoslot.Value); err != nil {
			fmt.Println("Fehler: Konnte Anzahl nicht konvertieren")
			errStr := "Tut mir leid - das habe ich nicht verstanden."
			echoResp.OutputSpeech(errStr).Card("heise online Top News", errStr)
			return
		}
	}
	speech := fmt.Sprintf(`<speak>heise online Top News - die letzten `+
		`<say-as interpret-as="number">%d</say-as> Nachrichten:`, newsCount)
	card := fmt.Sprintf("Die letzten %d Nachrichten: ", newsCount)
	feed := feedCache.Get()
	fmt.Printf("Feed: %p", feed)
	for k, v := range feed.Items {
		if k < newsCount {
			line := fmt.Sprintf(`<p>%s</p><p>%s</p>`, v.Title,
				v.Description)
			speech = fmt.Sprintf(`%s<break strength="x-strong"/>%s`, speech,
				line)
			card = fmt.Sprintf("%s\n%s - %s", card, v.Title, v.Description)
		} else {
			break
		}
	}
	speech = fmt.Sprintf("%s</speak>", speech)
	echoResp.OutputSpeechSSML(speech).Card("heise online Top-News", card)
	fmt.Printf("<---- Antworte mit %s\n", card)
}

// Da der Newsfeed asynchron im Hintergrund neu geladen wird muss der
// Zugriff synchronisiert werden. FeedCache realisiert das mit einem
// Mutex.
type FeedCache struct {
	lock sync.RWMutex
	feed *gofeed.Feed
}

func (c *FeedCache) Get() *gofeed.Feed {
	c.lock.RLock()
	defer c.lock.RUnlock()
	d := c.feed
	return d
}

func (c *FeedCache) Set(f *gofeed.Feed) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.feed = f
}
