package web

import (
	"bytes"
	"encoding/json"
	"gitlab.crans.org/nounous/ghostream/stream/srt"
	"html/template"
	"log"
	"net"
	"net/http"
	"strings"

	"github.com/markbates/pkger"
	"gitlab.crans.org/nounous/ghostream/internal/monitoring"
	"gitlab.crans.org/nounous/ghostream/stream/webrtc"
)

// Handle WebRTC session description exchange via POST
func viewerPostHandler(w http.ResponseWriter, r *http.Request) {
	// Limit response body to 128KB
	r.Body = http.MaxBytesReader(w, r.Body, 131072)

	// Get stream ID from URL, or from domain name
	path := r.URL.Path[1:]
	if cfg.OneStreamPerDomain {
		host := r.Host
		if strings.Contains(host, ":") {
			realHost, _, err := net.SplitHostPort(r.Host)
			if err != nil {
				log.Printf("Failed to split host and port from %s", r.Host)
				return
			}
			host = realHost
		}
		path = host
	}

	// Decode client description
	dec := json.NewDecoder(r.Body)
	dec.DisallowUnknownFields()
	remoteDescription := webrtc.SessionDescription{}
	if err := dec.Decode(&remoteDescription); err != nil {
		http.Error(w, "The JSON WebRTC offer is malformed", http.StatusBadRequest)
		return
	}

	// Exchange session descriptions with WebRTC stream server
	remoteSdpChan <- struct {
		StreamID          string
		RemoteDescription webrtc.SessionDescription
	}{StreamID: path, RemoteDescription: remoteDescription}
	localDescription := <-localSdpChan

	// Send server description as JSON
	jsonDesc, err := json.Marshal(localDescription)
	if err != nil {
		http.Error(w, "An error occurred while formating response", http.StatusInternalServerError)
		log.Println("An error occurred while sending session description", err)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	_, err = w.Write(jsonDesc)
	if err != nil {
		log.Println("An error occurred while sending session description", err)
	}

	// Increment monitoring
	monitoring.WebSessions.Inc()
}

func viewerGetHandler(w http.ResponseWriter, r *http.Request) {
	// Get stream ID from URL, or from domain name
	path := r.URL.Path[1:]
	if cfg.OneStreamPerDomain {
		host := r.Host
		if strings.Contains(host, ":") {
			realHost, _, err := net.SplitHostPort(r.Host)
			if err != nil {
				log.Printf("Failed to split host and port from %s", r.Host)
				return
			}
			host = realHost
		}
		path = host
	}

	// Render template
	data := struct {
		Cfg       *Options
		Path      string
		WidgetURL string
	}{Path: path, Cfg: cfg}

	// Compute the WidgetURL with the stream path
	b := &bytes.Buffer{}
	_ = template.Must(template.New("").Parse(cfg.WidgetURL)).Execute(b, data)
	data.WidgetURL = b.String()

	if err := templates.ExecuteTemplate(w, "base", data); err != nil {
		log.Println(err.Error())
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	// Increment monitoring
	monitoring.WebViewerServed.Inc()
}

// Handle site index and viewer pages
// POST requests are used to exchange WebRTC session descriptions
func viewerHandler(w http.ResponseWriter, r *http.Request) {
	// Validation on path
	if validPath.FindStringSubmatch(r.URL.Path) == nil {
		http.NotFound(w, r)
		log.Print(r.URL.Path)
		return
	}

	// Route depending on HTTP method
	switch r.Method {
	case http.MethodGet:
		viewerGetHandler(w, r)
	case http.MethodPost:
		viewerPostHandler(w, r)
	default:
		http.Error(w, "Sorry, only GET and POST methods are supported.", http.StatusBadRequest)
	}
}

func staticHandler() http.Handler {
	// Set up static files server
	staticFs := http.FileServer(pkger.Dir("/web/static"))
	return http.StripPrefix("/static/", staticFs)
}

func statisticsHandler(w http.ResponseWriter, r *http.Request) {
	// Display connected users stats, from WebRTC or streaming directly from a video player
	streamID := strings.Replace(r.URL.Path[7:], "/", "", -1)
	enc := json.NewEncoder(w)
	err := enc.Encode(struct {
		ConnectedViewers int
	}{webrtc.GetNumberConnectedSessions(streamID) + srt.GetNumberConnectedSessions(streamID)})
	if err != nil {
		http.Error(w, "Failed to generate JSON.", http.StatusInternalServerError)
		log.Printf("Failed to generate JSON: %s", err)
	}
}