package main

import (
	"context"
	"evening_detective/internal/app"
	"evening_detective/internal/services"
	"evening_detective/internal/services/story_service"
	proto "evening_detective/proto"
	"log"
	"net"
	"net/http"

	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
)

func main() {
	// Create a listener on TCP port
	lis, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatalln("Failed to listen:", err)
	}

	// Create a gRPC server object
	s := grpc.NewServer()
	// Attach the Greeter service to the server
	repository, err := services.NewRepository()
	if err != nil {
		panic(err)
	}
	storyService, err := story_service.NewStoryService()
	if err != nil {
		log.Fatalln(err)
	}
	proto.RegisterEveningDetectiveServer(
		s,
		app.NewServer(
			services.NewServices(
				repository,
				storyService,
			),
		),
	)
	// Serve gRPC server
	log.Println("Serving gRPC on 0.0.0.0:8080")
	go func() {
		log.Fatalln(s.Serve(lis))
	}()

	// Create a client connection to the gRPC server we just started
	// This is where the gRPC-Gateway proxies the requests
	conn, err := grpc.NewClient(
		"0.0.0.0:8080",
		grpc.WithTransportCredentials(insecure.NewCredentials()),
	)
	if err != nil {
		log.Fatalln("Failed to dial server:", err)
	}

	gwmux := runtime.NewServeMux(
		runtime.WithMetadata(func(ctx context.Context, request *http.Request) metadata.MD {
			teamId := request.Header.Get("X-Id")
			return metadata.Pairs("team-id", teamId)
		}),
		runtime.WithMetadata(func(ctx context.Context, request *http.Request) metadata.MD {
			password := request.Header.Get("X-Password")
			return metadata.Pairs("password", password)
		}),
	)
	// Register Greeter
	err = proto.RegisterEveningDetectiveHandler(context.Background(), gwmux, conn)
	if err != nil {
		log.Fatalln("Failed to register gateway:", err)
	}

	gwServer := &http.Server{
		Addr:    ":8090",
		Handler: cors(gwmux),
	}

	// Serve gRPC-Gateway server
	log.Println("Serving gRPC-Gateway on http://0.0.0.0:8090")
	go func() {
		log.Fatalln(gwServer.ListenAndServe())
	}()

	muxUser := http.NewServeMux()
	fileServerUser := http.FileServer(http.Dir("./static/user"))
	muxUser.Handle("/", fileServerUser)

	// Serve user web server
	log.Println("Serving user web on http://0.0.0.0:8100")
	go func() {
		log.Fatalln(http.ListenAndServe(":8100", muxUser))
	}()

	muxAdmin := http.NewServeMux()
	fileServerAdmin := http.FileServer(http.Dir("./static/admin"))
	muxAdmin.Handle("/", fileServerAdmin)

	// Serve admin web server
	log.Println("Serving admin web on http://0.0.0.0:8110")
	log.Fatalln(http.ListenAndServe(":8110", muxAdmin))
}

func cors(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE")
		w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization, ResponseType, X-Id, X-Password")
		if r.Method == "OPTIONS" {
			return
		}
		h.ServeHTTP(w, r)
	})
}
