package rss

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"local/rssmon3/config"
	"log"
	"net/http"
	"net/http/httptest"
	"os"
	"path"
	"reflect"
	"testing"
	"time"
)

func initRSSFeed() {
	os.Args = []string{"a", "-db", "map"}
	if err := config.New(); err != nil {
		panic(err)
	}
}

type mockStruct struct{}

func mockRSS() *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var v mockStruct
		base := reflect.TypeOf(v).PkgPath()
		f, err := os.Open(path.Join(os.Getenv("GOPATH"), "src", base, "./testdata/rss.xml"))
		if err != nil {
			panic(err)
		}
		io.Copy(w, f)
	}))
}

func TestRSSFeedEncodeDecode(t *testing.T) {
	initRSSFeed()

	f := newFeed("key")
	f.Updated = time.Now()
	f.TitleFilter = "a"
	f.ContentFilter = "b"
	f.Tags = []string{"c"}

	b, err := f.Encode()
	if err != nil {
		t.Fatal(err)
	}

	g := newFeed("key")
	if err := g.Decode(b); err != nil {
		t.Fatal(err)
	}

	fb, _ := json.Marshal(f)
	gb, _ := json.Marshal(f)
	if string(fb) != string(gb) {
		t.Errorf("%v => %v", *f, *g)
	}
}

func TestRSSFeedSaveLoad(t *testing.T) {
	initRSSFeed()

	f := newFeed("key")
	f.Updated = time.Now()
	f.TitleFilter = "a"
	f.ContentFilter = "b"
	f.Tags = []string{"c"}

	if err := f.save(); err != nil {
		t.Fatal(err)
	}

	g := newFeed("key")
	if err := g.Load(); err != nil {
		t.Fatal(err)
	}

	fb, _ := json.Marshal(f)
	gb, _ := json.Marshal(g)
	if string(fb) != string(gb) {
		t.Fatalf("%v != %v", f, g)
	}

	h := newFeed("key2")
	if err := h.Load(); err == nil {
		t.Fatal("can load nil feed")
	}
}

func TestRSSFeedPull(t *testing.T) {
	initRSSFeed()

	s := mockRSS()
	defer s.Close()

	f := newFeed("key")
	f.TitleFilter = "500"
	f.ContentFilter = "b"
	f.Tags = []string{"c"}
	f.URL = s.URL

	log.SetOutput(bytes.NewBuffer(nil))
	defer log.SetOutput(os.Stderr)
	if err := f.Pull(); err != nil {
		t.Fatal(err)
	}
	log.SetOutput(os.Stderr)

	if f.Updated.Format("2006-01-02 15:04:05") != "2019-06-18 19:00:00" {
		t.Errorf("updated is wrong: %v", f)
	}

	keys, err := config.Values().DB.List([]string{nsItems, f.Key})
	if err != nil {
		t.Fatal(err)
	}
	if len(keys) < 1 {
		t.Fatal(len(keys))
	}
	if keys[0] != "2018-07-10-19-00:https://roosterteeth.com/episode/rooster-teeth-podcast-2018-rooster-teeth-podcast-500" {
		t.Fatal(keys[0])
	}

	log.SetOutput(bytes.NewBuffer(nil))
	defer log.SetOutput(os.Stderr)
	if err := f.Pull(); err != nil {
		t.Fatal(err)
	}
	log.SetOutput(os.Stderr)
	keysB, err := config.Values().DB.List([]string{nsItems, f.Key})
	if err != nil {
		t.Fatal(err)
	}
	if fmt.Sprintf("%v", keys) != fmt.Sprintf("%v", keysB) {
		t.Fatalf("%v vs %v", keys, keysB)
	}

	itemKeys, err := f.List(5)
	if err != nil {
		t.Fatal(err)
	}
	if len(itemKeys) < 1 {
		t.Fatal(len(itemKeys))
	}
	if len(itemKeys) > 5 {
		t.Fatal(len(itemKeys))
	}
	if itemKeys[0] != "2018-07-10-19-00:https://roosterteeth.com/episode/rooster-teeth-podcast-2018-rooster-teeth-podcast-500" {
		t.Fatal(itemKeys[0])
	}

	items, err := f.Items(1)
	if err != nil {
		t.Fatal(err)
	}
	if len(items) < 1 {
		t.Fatal(len(items))
	}
	if items[0].ID() != itemKeys[0] {
		t.Fatalf("%v vs %v", items[0].ID(), itemKeys[0])
	}

	i := &Item{}
	if err := i.Load(itemKeys[0], f.Key); err != nil {
		t.Fatal(err)
	}
	if *i == (Item{}) {
		t.Fatal(i)
	}
	if i.Link == "" || i.Title == "" || i.Content == "" {
		t.Fatal(i)
	}
}

func TestRSSFeedListLimitedDescending(t *testing.T) {
	initRSSFeed()

	s := mockRSS()
	defer s.Close()

	f := newFeed("key")
	f.TitleFilter = "50."
	f.ContentFilter = "b"
	f.Tags = []string{"c"}
	f.URL = s.URL

	log.SetOutput(bytes.NewBuffer(nil))
	defer log.SetOutput(os.Stderr)
	if err := f.Pull(); err != nil {
		t.Fatal(err)
	}
	log.SetOutput(os.Stderr)

	itemKeys, err := f.List(5)
	if err != nil {
		t.Fatal(err)
	}
	if len(itemKeys) != 5 {
		t.Fatal(len(itemKeys))
	}

	for i := range itemKeys {
		if i > 0 && itemKeys[i] > itemKeys[i-1] {
			t.Error(itemKeys[i], ">", itemKeys[i-1])
		}
	}
}
