package main

import (
	"context"
	"io"
	"log"
	"net/http"

	"golang.org/x/time/rate"
)

type S struct {
	ctx     context.Context
	limiter *rate.Limiter
	config  Config
}

func (s *S) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if err := s.serveHTTP(w, r); err != nil {
		log.Println(s.Session(r.Context()), "//", r.URL.Path, "//", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (s *S) serveHTTP(w http.ResponseWriter, r *http.Request) error {
	if isV1(r) || isWS(r) {
		return s.serveAPI(w, r)
	}
	return s.serveStatic(w, r)
}

func (s *S) serveStatic(w http.ResponseWriter, r *http.Request) error {
	fs := http.Dir(s.config.Root)
	http.FileServer(fs).ServeHTTP(w, r)
	return nil
}

func (s *S) serveAPI(w http.ResponseWriter, r *http.Request) error {
	if err := s.injectContext(w, r); err == io.EOF {
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return nil
	} else if err != nil {
		return err
	}

	if isWS(r) {
		return s.serveWS(w, r)
	} else if isV1(r) {
		return s.serveV1(w, r)
	}

	http.NotFound(w, r)
	return nil
}

type Session struct {
	ID string
}

func (s *S) injectContext(w http.ResponseWriter, r *http.Request) error {
	id, err := r.Cookie("uuid")
	if err != nil || id.Value == "" {
		return io.EOF
	}
	ctx := r.Context()
	ctx = context.WithValue(ctx, "session", Session{
		ID: id.Value,
	})
	*r = *r.WithContext(ctx)
	return nil
}

func (s *S) Session(ctx context.Context) Session {
	v, _ := ctx.Value("session").(Session)
	return v
}
