package server

import (
	"encoding/json"
	"fmt"
	"local/router"
	"local/rssmon3/monitor"
	"local/rssmon3/rss"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

func (s *Server) Routes() error {
	handles := []struct {
		path    string
		handler http.HandlerFunc
	}{
		{path: fmt.Sprintf("/api/tag/%s", router.Wildcard), handler: s.tag},
		{path: fmt.Sprintf("/api/feed"), handler: s.feed},
	}
	for _, handle := range handles {
		if err := s.router.Add(handle.path, handle.handler); err != nil {
			return err
		}
	}
	return nil
}

func (s *Server) notFound(w http.ResponseWriter, r *http.Request) {
	http.NotFound(w, r)
	return
}

func (s *Server) userError(w http.ResponseWriter, r *http.Request, err error) {
	status := http.StatusBadRequest
	log.Printf("[userError] %d: %v", status, err)
	w.WriteHeader(status)
}

func (s *Server) error(w http.ResponseWriter, r *http.Request, err error) {
	status := http.StatusInternalServerError
	log.Printf("[error] %d: %v", status, err)
	w.WriteHeader(status)
}

func (s *Server) tag(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		s.notFound(w, r)
		return
	}
	limit, err := strconv.Atoi(r.URL.Query().Get("n"))
	if err != nil {
		limit = 20
	}
	tag := regexp.MustCompile("^.*\\/").ReplaceAllString(r.URL.Path, "")
	feeds, err := rss.TaggedFeeds(tag)
	if err != nil {
		s.error(w, r, err)
		return
	}
	items := []*rss.Item{}
	for _, feed := range feeds {
		feedItems, err := feed.Items(limit)
		if err != nil {
			s.error(w, r, err)
		}
		items = append(items, feedItems...)
	}
	if err := rss.WriteFeed(w, tag, items); err != nil {
		s.error(w, r, err)
		return
	}
}

func (s *Server) feed(w http.ResponseWriter, r *http.Request) {
	if r.Method != "PUT" {
		s.notFound(w, r)
		return
	}
	var putFeed struct {
		URL           string            `json:"url"`
		Interval      string            `json:"refresh"`
		TitleFilter   string            `json:"items"`
		Copyright     string            `json:"copyright"`
		ContentFilter string            `json:"content"`
		Tags          []string          `json:"tags"`
		Headers       map[string]string `json:"headers"`
		URL           string            `json:"url"`
		Interval      string            `json:"refresh"`
		TitleFilter   string            `json:"items"`
		Copyright     string            `json:"copyright"`
		ContentFilter string            `json:"content"`
		Tags          []string          `json:"tags"`
	}
	if err := json.NewDecoder(r.Body).Decode(&putFeed); err != nil {
		s.userError(w, r, err)
		return
	}
	if putFeed.Headers == nil {
		putFeed.Headers = map[string]string{}
	}
	putFeedHeaders, _ := json.Marshal(putFeed.Headers)
	interval, err := time.ParseDuration(putFeed.Interval)
	if err != nil {
		s.userError(w, r, err)
		return
	}
	f := &rss.Feed{
		Key:           putFeed.URL,
		URL:           putFeed.URL,
		TitleFilter:   putFeed.TitleFilter,
		ContentFilter: putFeed.ContentFilter,
		Tags:          putFeed.Tags,
		Copyright:     putFeed.Copyright,
		Headers:       putFeedHeaders,
	}
	if err := rss.SubmitFeed(f); err != nil {
		s.error(w, r, err)
		return
	}
	i, err := monitor.NewItem(f.Key, interval)
	if err != nil {
		s.error(w, r, err)
		return
	}
	s.Jobs <- i
}
