package handlers

import (
	"encoding/xml"
	"net/http"
	"net/url"
	"time"
)

type rssFeedXML struct {
	XMLName xml.Name      `xml:"rss"`
	Version string        `xml:"version,attr"`
	Channel rssChannelXML `xml:"channel"`
}

type rssChannelXML struct {
	Title       string       `xml:"title"`
	Link        string       `xml:"link"`
	Description string       `xml:"description"`
	Items       []rssItemXML `xml:"item"`
}

type rssItemXML struct {
	Title       string `xml:"title"`
	Link        string `xml:"link"`
	GUID        string `xml:"guid"`
	Description string `xml:"description,omitempty"`
	PubDate     string `xml:"pubDate,omitempty"`
}

func (h *handlers) repoFeedHandler(w http.ResponseWriter, r *http.Request) {
	repo, err := h.openPublicRepo(r.PathValue("name"), "")
	if err != nil {
		h.write404(w, r.URL.Path, err)
		return
	}

	desc, err := repo.Description()
	if err != nil {
		h.write500(w, err)
		return
	}

	repoName := repo.Name()
	feedLink, err := url.JoinPath("http://", h.c.Meta.Host, repoName)
	if err != nil {
		h.write500(w, err)
		return
	}

	feed := rssFeedXML{
		Version: "2.0",
		Channel: rssChannelXML{
			Title:       repoName,
			Link:        feedLink,
			Description: desc,
		},
	}

	// branches
	branches, err := repo.Branches()
	if err != nil {
		h.write500(w, err)
		return
	}

	for _, branch := range branches {
		href, _ := url.JoinPath("http://", h.c.Meta.Host, repoName, "tree", branch.Name)
		it := rssItemXML{
			Title: "branch: " + branch.Name,
			Link:  href,
			GUID:  href,
		}
		if !branch.LastUpdate.IsZero() {
			it.PubDate = branch.LastUpdate.Format(time.RFC1123Z)
		}
		feed.Channel.Items = append(feed.Channel.Items, it)
	}

	// tags
	tags, err := repo.Tags()
	if err == nil {
		for _, tag := range tags {
			href, _ := url.JoinPath("http://", h.c.Meta.Host, repoName, "tree", tag.Name())
			it := rssItemXML{
				Title:       "tag: " + tag.Name(),
				Link:        href,
				GUID:        href,
				Description: tag.Message(),
			}
			if !tag.When().IsZero() {
				it.PubDate = tag.When().Format(time.RFC1123Z)
			}
			feed.Channel.Items = append(feed.Channel.Items, it)
		}
	}

	w.Header().Set("Content-Type", "application/rss+xml")
	_, _ = w.Write([]byte(xml.Header))
	if err := xml.NewEncoder(w).Encode(feed); err != nil {
		h.write500(w, err)
		return
	}
}

func (h *handlers) indexFeedHandler(w http.ResponseWriter, r *http.Request) {
	repos, err := h.listPublicRepos()
	if err != nil {
		h.write500(w, err)
		return
	}

	feedLink, err := url.JoinPath("http://", h.c.Meta.Host)
	if err != nil {
		h.write500(w, err)
		return
	}

	feed := rssFeedXML{
		Version: "2.0",
		Channel: rssChannelXML{
			Title:       h.c.Meta.Host,
			Link:        feedLink,
			Description: h.c.Meta.Description,
		},
	}

	for _, repo := range repos {
		href, _ := url.JoinPath("http://", h.c.Meta.Host, repo.Name)
		it := rssItemXML{
			Title:       repo.Name,
			Link:        href,
			GUID:        href,
			Description: repo.Desc,
		}
		if !repo.LastCommit.IsZero() {
			it.PubDate = repo.LastCommit.Format(time.RFC1123Z)
		}
		feed.Channel.Items = append(feed.Channel.Items, it)
	}

	w.Header().Set("Content-Type", "application/rss+xml")
	_, _ = w.Write([]byte(xml.Header))
	if err := xml.NewEncoder(w).Encode(feed); err != nil {
		h.write500(w, err)
		return
	}
}
