package server

import (
	"crypto/tls"
	"log"
	"net"
	"time"

	"github.com/go-redis/redis/v8"
	"github.com/gofiber/fiber/v2"
	"github.com/jackc/pgx/v5/pgxpool"

	"git.ego.freeddns.org/egommerce/api-entities/common/dto"
	"git.ego.freeddns.org/egommerce/go-api-pkg/fluentd"
)

type (
	Server struct {
		*fiber.App

		ID       string
		addr     string // e.g. "127.0.0.1:443"
		handlers map[string]any
	}
	HeaderRequestID struct {
		RequestID string `reqHeader:"x-request-id"`
	}
)

func New(c *Config) *Server {
	return &Server{
		ID: c.ID,
		App: fiber.New(fiber.Config{
			AppName:      c.ID,
			ServerHeader: c.Name + ":" + c.ID,
			ReadTimeout:  c.ReadTimeout * time.Millisecond,
			WriteTimeout: c.WriteTimeout * time.Millisecond,
			IdleTimeout:  c.IdleTimeout * time.Millisecond,
		}),
		addr:     c.NetAddr,
		handlers: make(map[string]any),
	}
}

func (s *Server) Start() error {
	SetupMiddleware(s)
	SetupRouter(s)

	// fmt.Printf("Starting server at: %s...\n", s.addr)
	crt, err := tls.LoadX509KeyPair("certs/identity-svc.crt", "certs/identity-svc.key")
	if err != nil {
		log.Fatal(err)
	}
	tlsCnf := &tls.Config{Certificates: []tls.Certificate{crt}}

	ln, _ := net.Listen("tcp", s.addr)
	ln = tls.NewListener(ln, tlsCnf)

	return s.Listener(ln)
}

func (s *Server) RegisterHandler(name string, fn func() any) {
	// fmt.Printf("Registering plugin(with handler): %s... OK\n", name)
	s.handlers[name] = fn()
}

func (s *Server) OnShutdown() {
	s.GetLogger().Log("Server %s is going down...", s.ID)

	// s.GetEventBus().Close()
	s.GetDatabase().Close()
	s.GetLogger().Log("Gone.")
	s.GetLogger().Close()

	s.Shutdown()
}

func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) {
	var hdr = new(HeaderRequestID)
	if err := c.ReqHeaderParser(hdr); err != nil {
		return "", err
	}

	return hdr.RequestID, nil
}

func (s *Server) Error(c *fiber.Ctx, code int, msg string) error {
	return c.Status(code).JSON(dto.ErrorResponseDTO{Error: msg})
}

// Plugin helper funcitons
func (s *Server) GetCache() *redis.Client {
	return (s.handlers["cache"]).(*redis.Client)
}

func (s *Server) GetDatabase() *pgxpool.Pool { // FIXME hardcoded index issue
	return (s.handlers["database"]).(*pgxpool.Pool)
}

// func (s *Server) GetEventBus() *amqp.Channel {
// 	return (s.handlers["eventbus"]).(*amqp.Channel)
// }

func (s *Server) GetLogger() *fluentd.Logger {
	return (s.handlers["logger"]).(*fluentd.Logger)
}
