package server

import (
	"context"
	"errors"
	"fmt"
	"net"
	"net/http"
	"strings"
	"time"

	"bufio"
	"io"

	"git.pyer.club/kingecg/gohttpd/model"
	logger "git.pyer.club/kingecg/gologger"
	"github.com/soheilhy/cmux"
)

var ServerManager map[string]*ServerListener = make(map[string]*ServerListener)

func makeMatcher(name string, s *ServerListener) cmux.Matcher {
	return func(r io.Reader) bool {
		if s.ServerCount() == 1 {
			return true
		}
		req, err := http.ReadRequest(bufio.NewReader(r))
		if err != nil {
			return false
		}
		return strings.HasPrefix(req.Host, name)
	}
}

type sl struct {
	net.Listener
	closed bool
}

func (sl *sl) Accept() (net.Conn, error) {
	if sl.closed {
		return nil, errors.New("closed")
	}

	return sl.Listener.Accept()
}

func (sl *sl) Close() error {
	sl.closed = true
	return nil
}

type Server struct {
	Conf   *model.HttpServerConfig
	Closed bool
	*http.Server
	l *sl
}

func (s *Server) Renew() {
	s.Server = &http.Server{
		Handler: s.Handler,
	}
}

type ServerListener struct {
	port     int
	listener cmux.CMux
	servers  map[string]*Server
}

func (s *ServerListener) AddServer(name string, server *Server) {
	s.servers[name] = server
}

func (s *ServerListener) ServerCount() int {
	return len(s.servers)
}

func (s *ServerListener) StartServer(name string) {
	server, ok := s.servers[name]
	serverName := server.Conf.ServerName
	if !ok {
		panic("No named server")
	}

	go func() {
		var err error
		defer func() {
			l := logger.GetLogger("ServerListener")
			if err != nil {
				if err == http.ErrServerClosed {
					server.Closed = true

				} else {
					l.Error("Server error:", err)
				}

			}
			l.Info("Server stopped:", name)
		}()
		if server.Closed {
			server.Renew()
		}
		if server.l == nil {
			server.l = &sl{
				Listener: s.listener.Match(makeMatcher(serverName, s)),
			}
		}

		if server.Conf.CertFile != "" && server.Conf.KeyFile != "" {
			err = server.ServeTLS(server.l, server.Conf.CertFile, server.Conf.KeyFile)
		} else {
			err = server.Serve(server.l)
		}
	}()

	// return server.Serve(l)
}

func (s *ServerListener) StopServer(name string) error {
	server, ok := s.servers[name]
	if !ok {
		return nil
	}
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	return server.Shutdown(ctx)
}

// Start 方法用于并发启动 ServerListener 中所有注册的服务器。
// 它会为每个服务器创建一个新的 goroutine 来启动，以确保各个服务器可以独立运行。
func (s *ServerListener) Start() {
	// 遍历 ServerListener 中所有注册的服务器
	for name, _ := range s.servers {
		// 为每个服务器启动一个新的 goroutine 来执行启动操作
		s.StartServer(name)
	}
}

func (s *ServerListener) ShutDown() {
	// may need add wait group
	for _, server := range s.servers {
		server.Shutdown(context.Background())
	}
	s.listener.Close()
}

func (s *ServerListener) Serve() {
	l := logger.GetLogger("Listener")
	l.Debug("listen on :", s.port)
	go s.listener.Serve()
}

func NewServerListener(port int) *ServerListener {
	listenStr := fmt.Sprintf(":%d", port)
	l, err := net.Listen("tcp", listenStr)

	if err != nil {
		l := logger.GetLogger("ServerListener")
		l.Error("Listen error:", err)
	}
	muxer := cmux.New(l)
	s := &ServerListener{port: port, listener: muxer, servers: make(map[string]*Server)}
	return s
}

func AddServer(name string, server *Server, port int) {
	listenStr := fmt.Sprintf(":%d", port)
	listener, ok := ServerManager[listenStr]
	if !ok {
		listener = NewServerListener(port)
		ServerManager[listenStr] = listener
	}
	listener.AddServer(name, server)
}

func AddServerWithConfig(conf *model.HttpServerConfig) {
	mux := NewServeMux(conf)
	s := &http.Server{
		Handler: mux,
	}
	name := conf.Name
	port := conf.Port
	ss := &Server{
		Server: s,
		Conf:   conf,
	}
	AddServer(name, ss, port)
}

func StopServer(name string, port int) {
	listenStr := fmt.Sprintf(":%d", port)
	listener, ok := ServerManager[listenStr]
	if !ok {
		return
	}
	listener.StopServer(name)
}

func StartServer(name string, port int) {
	listenStr := fmt.Sprintf(":%d", port)
	listener, ok := ServerManager[listenStr]
	if !ok {
		return
	}
	listener.StartServer(name)
}
