package main

import (
	"context"
	"embed"
	"io/fs"
	"log"
	"net"
	"net/http"
	"pinned_message/internal/app"
	"pinned_message/internal/config"
	"pinned_message/internal/modules/data_parser"
	"pinned_message/internal/modules/date_parser"
	"pinned_message/internal/services"
	"pinned_message/internal/services/schedule_parser"
	"pinned_message/internal/services/schedule_storage"
	proto "pinned_message/proto"

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

const (
	tcpPort    = ":8200"
	gwPort     = ":8210"
	clientPort = ":8220"
)

//go:embed static/user/*
var userFS embed.FS

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

	// Create a gRPC server object
	s := grpc.NewServer()

	ctx := context.Background()
	scheduleStorage := schedule_storage.NewScheduleStorage(config.GetScheduleFilepath())
	scheduleParser := schedule_parser.NewScheduleParser(
		data_parser.NewGoogleTableScheduleParser(),
		date_parser.NewDateParser(),
		scheduleStorage,
	)
	go func() {
		scheduleParser.Run(ctx)
	}()

	// Attach the Greeter service to the server
	proto.RegisterPinnedMessageServer(
		s,
		app.NewServer(
			services.NewServices(
				scheduleStorage,
			),
		),
	)
	// Serve gRPC server
	log.Println("Serving gRPC on 0.0.0.0" + tcpPort)
	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"+tcpPort,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
	)
	if err != nil {
		log.Fatalln("Failed to dial server:", err)
	}

	gwmux := runtime.NewServeMux()
	// Register Greeter
	err = proto.RegisterPinnedMessageHandler(context.Background(), gwmux, conn)
	if err != nil {
		log.Fatalln("Failed to register gateway:", err)
	}

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

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

	muxUser := http.NewServeMux()
	subUserFS, err := fs.Sub(userFS, "static/user")
	if err != nil {
		log.Fatalln(err)
	}
	fileServerUser := http.FileServer(http.FS(subUserFS))
	muxUser.Handle("/", fileServerUser)

	// Serve admin web server
	log.Println("Serving user web on http://0.0.0.0" + clientPort)
	log.Fatalln(http.ListenAndServe(clientPort, muxUser))
}

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, PUT, 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)
	})
}
