package backend

import (
	"errors"
	"fmt"
	"io"
	"os"

	"git.streifling.com/jason/atom"
)

func GenerateAtomFeed(c *Config, db *DB) (*string, error) {
	feed := atom.NewFeed(c.Title)
	feed.ID = atom.NewID("urn:feed:1")
	feed.Subtitle = atom.NewText("text", c.Description)
	if feed.Subtitle == nil {
		return nil, errors.New("feed subtitle was not created")
	}

	linkID := feed.AddLink(atom.NewLink(c.Link))
	feed.Links[linkID].Rel = "self"

	feed.Generator = atom.NewGenerator("cpolis")
	feed.Generator.URI = "https://git.streifling.com/jason/cpolis"
	feed.Generator.Version = c.Version

	articles, err := db.GetCertainArticles("published", true)
	if err != nil {
		return nil, fmt.Errorf("error getting published articles for Atom feed: %v", err)
	}

	for _, article := range articles {
		articleTitle, err := ConvertToPlain(article.Title)
		if err != nil {
			return nil, fmt.Errorf("error converting title to plain text for Atom feed: %v", err)
		}
		entry := atom.NewEntry(articleTitle)
		entry.ID = atom.NewID(fmt.Sprint("urn:entry:", article.ID))
		entry.Published = atom.NewDate(article.Created)
		entry.Content = atom.NewContent(atom.OutOfLine, "text/html", fmt.Sprint(c.Domain, "/article/serve/", article.UUID))
		if entry.Content == nil {
			return nil, errors.New("entry content was not created")
		}

		if article.AutoGenerated {
			entry.Summary = atom.NewText("text", "automatically generated")
			if entry.Summary == nil {
				return nil, errors.New("entry summary was not created")
			}
		} else {
			articleSummary, err := ConvertToPlain(article.Summary)
			if err != nil {
				return nil, fmt.Errorf("error converting description to plain text for Atom feed: %v", err)
			}
			entry.Summary = atom.NewText("text", articleSummary)
			if entry.Summary == nil {
				return nil, errors.New("entry summary was not created")
			}
		}

		if len(article.BannerLink) > 0 {
			linkID := entry.AddLink(atom.NewLink(c.Domain + "/image/serve/" + article.BannerLink))
			entry.Links[linkID].Rel = "enclosure"
			entry.Links[linkID].Type = "image/webp"
		}

		authors, err := db.GetArticleAuthors(c, article.ID)
		if err != nil {
			return nil, fmt.Errorf("error getting article's authors for Atom feed: %v", err)
		}
		for _, author := range authors {
			user, err := db.GetUser(c, author.ID)
			if err != nil {
				return nil, fmt.Errorf("error getting user info for Atom feed: %v", err)
			}

			authorID := entry.AddAuthor(atom.NewPerson(user.FirstName + " " + user.LastName))
			entry.Authors[authorID].URI = c.Domain + "/image/serve/" + user.ProfilePicLink
		}

		contributors, err := db.GetArticleContributors(c, article.ID)
		if err != nil {
			return nil, fmt.Errorf("error getting article's contributors for Atom feed: %v", err)
		}
		for _, contributor := range contributors {
			user, err := db.GetUser(c, contributor.ID)
			if err != nil {
				return nil, fmt.Errorf("error getting user info for Atom feed: %v", err)
			}

			contributorID := entry.AddContributor(atom.NewPerson(user.FirstName + " " + user.LastName))
			entry.Contributors[contributorID].URI = c.Domain + "/image/serve/" + user.ProfilePicLink
		}

		tags, err := db.GetArticleTags(article.ID)
		if err != nil {
			return nil, fmt.Errorf("error getting tags for articles for Atom feed: %v", err)
		}
		for _, tag := range tags {
			entry.AddCategory(atom.NewCategory(tag.Name))
		}

		if article.IsInIssue || article.AutoGenerated {
			entry.AddCategory(atom.NewCategory(fmt.Sprint("Orient Express ", article.IssueID)))
		}
		if article.AutoGenerated {
			entry.AddCategory(atom.NewCategory("autogenerated"))
		}

		entry.Updated = atom.NewDate(article.Created)
		feed.AddEntry(entry)
	}

	if err = feed.Check(); err != nil {
		return nil, fmt.Errorf("error checking Atom feed: %v", err)
	}

	atom, err := feed.ToXML("UTF-8")
	if err != nil {
		return nil, fmt.Errorf("error converting Atom feed to XML: %v", err)
	}

	return &atom, nil
}

func SaveAtomFeed(filename string, feed *string) error {
	file, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("error creating file for Atom feed: %v", err)
	}
	defer file.Close()
	if err = file.Chmod(0644); err != nil {
		return fmt.Errorf("error setting permissions for Atom file: %v", err)
	}

	if _, err = io.WriteString(file, *feed); err != nil {
		return fmt.Errorf("error writing to Atom file: %v", err)
	}

	return nil
}