package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/mmcdole/gofeed"
)

// layoutUS is a human friendly date format.
const layoutUS = "January 2, 2006"

// feed is an RSS feed.
type feed struct {
	Slug  string `json:"slug"`  // Slug for the RSS feed
	Title string `json:"title"` // Title of the RSS feed
	Url   string `json:"url"`   // URL of the RSS feed
}

// item is a single RSS feed item.
type item struct {
	link      string
	published *time.Time
	title     string
}

// getFeeds retrieves all feeds from the FvA website API.
func getFeeds() ([]feed, error) {
	var feeds []feed

	url := "https://test.fva.wtf/api/anarchokrant-list"
	resp, err := http.Get(url)
	if err != nil {
		return feeds, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return feeds, err
	}

	if err := json.Unmarshal(body, &feeds); err != nil {
		return feeds, err
	}

	return feeds, nil
}

// parseRSSFeed parses a RSS feed.
func parseRSSFeed(url string) (gofeed.Feed, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()

	feedParser := gofeed.NewParser()
	feed, err := feedParser.ParseURLWithContext(url, ctx)
	if err != nil {
		return gofeed.Feed{}, fmt.Errorf("parseRSSFeed: unable to parse %s: %w", url, err)
	}

	return *feed, nil
}

func linksFromFeed(day int, feed string, ch chan<- []item) {
	var items []item

	parsed, err := parseRSSFeed(feed)
	if err != nil {
		log.Printf("failed to parse feed: %s\n\n", feed)
		ch <- items
	}

	now := time.Now()
	lastMonth := time.Date(now.Year(), now.Month()-1, day, 0, 0, 0, 0, time.UTC)

	for _, i := range parsed.Items {
		if i.PublishedParsed.After(lastMonth) {
			items = append(items, item{
				link:      i.Link,
				published: i.PublishedParsed,
				title:     i.Title,
			})
		}
	}

	ch <- items
}

// show outputs an item.
func (i item) show() {
	fmt.Printf("%s\n%s\n%s\n\n", i.published.Format(layoutUS), i.title, i.link)
}

func main() {
	var dayFlag int
	flag.IntVar(&dayFlag, "d", 28, "day of last month")
	flag.Parse()

	feeds, err := getFeeds()
	if err != nil {
		log.Fatal(err)
	}

	ch := make(chan []item, len(feeds))
	for _, feed := range feeds {
		go linksFromFeed(dayFlag, feed.Url, ch)
	}

	for range feeds {
		items := <-ch
		for _, item := range items {
			item.show()
		}
	}
}
