package api

import (
	"fmt"
	"net/http"

	"github.com/jixwanwang/apiutils"

	"goji.io"
	"goji.io/pat"
	"golang.org/x/net/context"

	"code.justin.tv/common/config"
	"code.justin.tv/common/golibs/errorlogger"
	"code.justin.tv/common/twitchhttp"
	"code.justin.tv/live/yt-live-annotations/youtube"
	"code.justin.tv/web/jax/client"
	"github.com/cactus/go-statsd-client/statsd"
)

// Server is a server type
type Server struct {
	*goji.Mux
	backend     Backend
	yt          YT
	jax         Jax
	errorLogger errorlogger.ErrorLogger
	stats       statsd.Statter
}

type Backend interface {
	DisableAnnotations(ctx context.Context, userID string) error
	GetAnnotationsEnabled(ctx context.Context, userID string) (bool, error)
	UpdateAnnotationsTimestamp(ctx context.Context, userID string) error
	ScanAnnotationsEnabledUsers() (chan string, chan error)
	ScanAnnotationsEnabledUsersAll() (chan string, chan error)
}

type YT interface {
	ClearYoutubeAnnotations(ctx context.Context, userID string) error
	SetYoutubeAnnotationsStatus(ctx context.Context, userID string, status int) error
}

type Jax interface {
	GetStreamByID(ctx context.Context, userID string, opts *jax.StreamOptions, reqOpts *twitchhttp.ReqOpts) (*jax.Streams, error)
}

// NewServer creates a new server
func NewServer(b Backend, yt YT, jx Jax) (*Server, error) {
	s := &Server{
		Mux:         twitchhttp.NewServer(),
		backend:     b,
		yt:          yt,
		jax:         jx,
		errorLogger: config.RollbarErrorLogger(),
		stats:       config.Statsd(),
	}

	s.HandleFuncC(pat.Get("/health"), s.HealthCheck)

	s.HandleFuncC(pat.Post("/"), s.processMessage)
	s.HandleFuncC(pat.Post("/cleanup"), s.cleanupJob)
	s.HandleFuncC(pat.Post("/sunset"), s.sunsetJob)
	return s, nil
}

// HealthCheck implementes a health check endpoint
func (s *Server) HealthCheck(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	_, err := s.backend.GetAnnotationsEnabled(ctx, "0")
	if err != nil {
		s.serveError(w, r, http.StatusInternalServerError, fmt.Errorf("dyanmo error"), "health")
		return
	}
	s.serveSuccess(w, "health")
}

func (S *Server) serveSuccess(w http.ResponseWriter, statName string) {
	S.stats.Inc(fmt.Sprintf("worker_api.%v.200", statName), 1, 0.5)
	w.Write([]byte("OK"))
}

func (S *Server) serveError(w http.ResponseWriter, r *http.Request, status int, err error, statName string) {
	S.stats.Inc(fmt.Sprintf("worker_api.%v.%v", statName, status), 1, 0.5)

	errRes := apiutils.NewErrorResponse(status, err.Error())
	apiutils.ServeError(w, errRes)

	if S.errorLogger != nil && !youtube.ShouldIgnoreError(errRes) {
		S.errorLogger.RequestError(r, errRes)
	}
}
