package lib

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
)

// Fetcher is the interface for a fetcher.
type Fetcher interface {
	Name() string
	Fetch() []Message
}

// BaseFetcher contains common fields for all fetchers.
type BaseFetcher struct {
	BaseURL      string
	Token        string
	Cache        *Cache
	ContentLimit int
}

// TryCreateMessage checks the cache and creates a Message if the value has changed.
func (b *BaseFetcher) TryCreateMessage(channel, cacheKey, cacheValue, title, url string) *Message {
	if b.Cache.TryUpdate(cacheKey, cacheValue) {
		return &Message{
			Channel: channel,
			Title:   title,
			URL:     url,
		}
	}
	return nil
}

// FetcherRequest represents a common HTTP request configuration.
type FetcherRequest struct {
	BaseURL string
	Path    string
	Method  string
	Headers map[string]string
	Body    []byte
}

// Run executes the HTTP request and decodes the JSON response into target.
func (r FetcherRequest) Run(target interface{}) error {
	url := r.BaseURL + r.Path

	var body io.Reader
	if r.Body != nil {
		body = bytes.NewBuffer(r.Body)
	}

	req, err := http.NewRequest(r.Method, url, body)
	if err != nil {
		return err
	}

	for key, value := range r.Headers {
		req.Header.Set(key, value)
	}

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	return json.NewDecoder(res.Body).Decode(target)
}
