package swagger_api

import (
	"embed"
	"encoding/json"
	"net/http"
	"net/url"

	"github.com/go-kratos/kratos/v2/api/metadata"
	"github.com/go-kratos/kratos/v2/transport/http/binding"
	"github.com/gorilla/mux"
)

//go:embed q/swagger-ui/*
var staticFS embed.FS

// NewHandler creates a traditional handler with service selection dropdown
func NewHandler(servicesList []string, skipError bool) http.Handler {
	service := New(skipError)
	r := mux.NewRouter()

	r.HandleFunc("/q/services", func(w http.ResponseWriter, r *http.Request) {
		if len(servicesList) > 0 {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(200)
			reply := map[string][]string{
				"services": servicesList,
			}
			json.NewEncoder(w).Encode(reply)
		} else {
			services, err := service.ListServices(r.Context(), &metadata.ListServicesRequest{})
			if err != nil {
				w.WriteHeader(500)
				w.Write([]byte(err.Error()))
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(200)
			json.NewEncoder(w).Encode(services)
		}
	}).Methods("GET")

	r.HandleFunc("/q/service/{name}", func(w http.ResponseWriter, r *http.Request) {
		raws := mux.Vars(r)
		vars := make(url.Values, len(raws))
		for k, v := range raws {
			vars[k] = []string{v}
		}
		var in metadata.GetServiceDescRequest
		if err := binding.BindQuery(vars, &in); err != nil {
			w.WriteHeader(400)
			w.Write([]byte(err.Error()))
			return
		}
		content, err := service.GetServiceOpenAPI(r.Context(), &in)
		if err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write([]byte(content))
	}).Methods("GET")

	staticServer := http.FileServer(http.FS(staticFS))
	sh := http.StripPrefix("", staticServer)
	r.PathPrefix("/q/swagger-ui").Handler(sh)
	return r
}

// NewMergedHandler creates a handler that shows all services merged in one page
// title: the title for the merged API document
// description: the description for the merged API document
func NewMergedHandler(servicesList []string, title, description string, skipError bool) http.Handler {
	service := New(skipError)
	r := mux.NewRouter()

	// Return a single "merged" service for Swagger UI to load
	r.HandleFunc("/q/services", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		reply := map[string][]string{
			"services": {"all"},
		}
		json.NewEncoder(w).Encode(reply)
	}).Methods("GET")

	// Handle the merged service request
	r.HandleFunc("/q/service/{name}", func(w http.ResponseWriter, r *http.Request) {
		raws := mux.Vars(r)
		serviceName := raws["name"]

		// Only handle "all" request
		if serviceName != "all" {
			w.WriteHeader(404)
			w.Write([]byte("only 'all' is supported in merged mode"))
			return
		}

		content, err := service.GetAllServicesOpenAPI(r.Context(), servicesList, title, description)
		if err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write([]byte(content))
	}).Methods("GET")

	staticServer := http.FileServer(http.FS(staticFS))
	sh := http.StripPrefix("", staticServer)
	r.PathPrefix("/q/swagger-ui").Handler(sh)
	return r
}
