// ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
// 🤖 Github Repository: https://github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io

package fiber

import (
	
	
	
	
	
	
	
	
	
	
	
	
	

	
	
	

	
)

const (
	globalIpv4Addr = "0.0.0.0"
)

// Listener can be used to pass a custom listener.
func ( *App) ( net.Listener) error {
	// prepare the server for the start
	.startupProcess()

	// run hooks
	.runOnListenHooks(.prepareListenData(.Addr().String(), getTLSConfig() != nil))

	// Print startup message
	if !.config.DisableStartupMessage {
		.startupMessage(.Addr().String(), getTLSConfig() != nil, "")
	}

	// Print routes
	if .config.EnablePrintRoutes {
		.printRoutesMessage()
	}

	// Prefork is not supported for custom listeners
	if .config.Prefork {
		log.Warn("Prefork isn't supported for custom listeners.")
	}

	// Start listening
	return .server.Serve()
}

// Listen serves HTTP requests from the given addr.
//
//	app.Listen(":8080")
//	app.Listen("127.0.0.1:8080")
func ( *App) ( string) error {
	// Start prefork
	if .config.Prefork {
		return .prefork(.config.Network, , nil)
	}

	// Setup listener
	,  := net.Listen(.config.Network, )
	if  != nil {
		return fmt.Errorf("failed to listen: %w", )
	}

	// prepare the server for the start
	.startupProcess()

	// run hooks
	.runOnListenHooks(.prepareListenData(.Addr().String(), false))

	// Print startup message
	if !.config.DisableStartupMessage {
		.startupMessage(.Addr().String(), false, "")
	}

	// Print routes
	if .config.EnablePrintRoutes {
		.printRoutesMessage()
	}

	// Start listening
	return .server.Serve()
}

// ListenTLS serves HTTPS requests from the given addr.
// certFile and keyFile are the paths to TLS certificate and key file:
//
//	app.ListenTLS(":8080", "./cert.pem", "./cert.key")
func ( *App) (, ,  string) error {
	// Check for valid cert/key path
	if len() == 0 || len() == 0 {
		return errors.New("tls: provide a valid cert or key path")
	}

	// Set TLS config with handler
	,  := tls.LoadX509KeyPair(, )
	if  != nil {
		return fmt.Errorf("tls: cannot load TLS key pair from certFile=%q and keyFile=%q: %w", , , )
	}

	return .ListenTLSWithCertificate(, )
}

// ListenTLS serves HTTPS requests from the given addr.
// cert is a tls.Certificate
//
//	app.ListenTLSWithCertificate(":8080", cert)
func ( *App) ( string,  tls.Certificate) error {
	 := &TLSHandler{}
	 := &tls.Config{
		MinVersion: tls.VersionTLS12,
		Certificates: []tls.Certificate{
			,
		},
		GetCertificate: .GetClientInfo,
	}

	// Prefork is supported
	if .config.Prefork {
		return .prefork(.config.Network, , )
	}

	// Setup listener
	,  := net.Listen(.config.Network, )
	 = tls.NewListener(, )
	if  != nil {
		return fmt.Errorf("failed to listen: %w", )
	}

	// prepare the server for the start
	.startupProcess()

	// run hooks
	.runOnListenHooks(.prepareListenData(.Addr().String(), getTLSConfig() != nil))

	// Print startup message
	if !.config.DisableStartupMessage {
		.startupMessage(.Addr().String(), true, "")
	}

	// Print routes
	if .config.EnablePrintRoutes {
		.printRoutesMessage()
	}

	// Attach the tlsHandler to the config
	.SetTLSHandler()

	// Start listening
	return .server.Serve()
}

// ListenMutualTLS serves HTTPS requests from the given addr.
// certFile, keyFile and clientCertFile are the paths to TLS certificate and key file:
//
//	app.ListenMutualTLS(":8080", "./cert.pem", "./cert.key", "./client.pem")
func ( *App) (, , ,  string) error {
	// Check for valid cert/key path
	if len() == 0 || len() == 0 {
		return errors.New("tls: provide a valid cert or key path")
	}

	,  := tls.LoadX509KeyPair(, )
	if  != nil {
		return fmt.Errorf("tls: cannot load TLS key pair from certFile=%q and keyFile=%q: %w", , , )
	}

	,  := os.ReadFile(filepath.Clean())
	if  != nil {
		return fmt.Errorf("failed to read file: %w", )
	}
	 := x509.NewCertPool()
	.AppendCertsFromPEM()

	return .ListenMutualTLSWithCertificate(, , )
}

// ListenMutualTLSWithCertificate serves HTTPS requests from the given addr.
// cert is a tls.Certificate and clientCertPool is a *x509.CertPool:
//
//	app.ListenMutualTLS(":8080", cert, clientCertPool)
func ( *App) ( string,  tls.Certificate,  *x509.CertPool) error {
	 := &TLSHandler{}
	 := &tls.Config{
		MinVersion: tls.VersionTLS12,
		ClientAuth: tls.RequireAndVerifyClientCert,
		ClientCAs:  ,
		Certificates: []tls.Certificate{
			,
		},
		GetCertificate: .GetClientInfo,
	}

	// Prefork is supported
	if .config.Prefork {
		return .prefork(.config.Network, , )
	}

	// Setup listener
	,  := tls.Listen(.config.Network, , )
	if  != nil {
		return fmt.Errorf("failed to listen: %w", )
	}

	// prepare the server for the start
	.startupProcess()

	// run hooks
	.runOnListenHooks(.prepareListenData(.Addr().String(), getTLSConfig() != nil))

	// Print startup message
	if !.config.DisableStartupMessage {
		.startupMessage(.Addr().String(), true, "")
	}

	// Print routes
	if .config.EnablePrintRoutes {
		.printRoutesMessage()
	}

	// Attach the tlsHandler to the config
	.SetTLSHandler()

	// Start listening
	return .server.Serve()
}

// prepareListenData create an slice of ListenData
func ( *App) ( string,  bool) ListenData { //revive:disable-line:flag-parameter // Accepting a bool param named isTLS if fine here
	,  := parseAddr()
	if  == "" {
		if .config.Network == NetworkTCP6 {
			 = "[::1]"
		} else {
			 = globalIpv4Addr
		}
	}

	return ListenData{
		Host: ,
		Port: ,
		TLS:  ,
	}
}

// startupMessage prepares the startup message with the handler number, port, address and other information
func ( *App) ( string,  bool,  string) { //nolint: revive // Accepting a bool param named isTLS if fine here
	// ignore child processes
	if IsChild() {
		return
	}

	// Alias colors
	 := .config.ColorScheme

	 := func( string,  int) string {
		 :=  - len()
		 := ""
		for  := 0;  < ; ++ {
			 += "."
		}
		if  == "Disabled" {
			 += " " + 
		} else {
			 += fmt.Sprintf(" %s%s%s", .Cyan, , .Black)
		}
		return 
	}

	 := func( string,  int) string {
		const  = 2
		 := strconv.Itoa(( - len()) / )
		 := fmt.Sprintf("%"++"s", " ")
		 += 
		 += fmt.Sprintf("%"++"s", " ")
		if len() <  {
			 += " "
		}
		return 
	}

	 := func( string,  int) string {
		const  = 2
		 := strconv.Itoa(( - runewidth.StringWidth()) / )
		 := fmt.Sprintf("%"++"s", " ")
		 += fmt.Sprintf("%s%s%s", .Cyan, , .Black)
		 += fmt.Sprintf("%"++"s", " ")
		if runewidth.StringWidth()-10 <  && runewidth.StringWidth()%2 == 0 {
			// add an ending space if the length of str is even and str is not too long
			 += " "
		}
		return 
	}

	 := func( string,  int) string {
		 :=  - len()
		 := 
		for  := 0;  < ; ++ {
			 += " "
		}
		return 
	}

	,  := parseAddr()
	if  == "" {
		if .config.Network == NetworkTCP6 {
			 = "[::1]"
		} else {
			 = globalIpv4Addr
		}
	}

	 := schemeHTTP
	if  {
		 = schemeHTTPS
	}

	 := "Disabled"
	if .config.Prefork {
		 = "Enabled"
	}

	 := strconv.Itoa(runtime.GOMAXPROCS(0))
	if !.config.Prefork {
		 = "1"
	}

	const  = 49
	 := .Black + " ┌───────────────────────────────────────────────────┐\n"
	if .config.AppName != "" {
		 += " │ " + (.config.AppName, ) + " │\n"
	}
	 += " │ " + ("Fiber v"+Version, ) + " │\n"

	if  == globalIpv4Addr {
		 += " │ " + (fmt.Sprintf("%s://127.0.0.1:%s", , ), ) + " │\n" +
			" │ " + (fmt.Sprintf("(bound on host 0.0.0.0 and port %s)", ), ) + " │\n"
	} else {
		 += " │ " + (fmt.Sprintf("%s://%s:%s", , , ), ) + " │\n"
	}

	 += fmt.Sprintf(
		" │                                                   │\n"+
			" │ Handlers %s  Processes %s │\n"+
			" │ Prefork .%s  PID ....%s │\n"+
			" └───────────────────────────────────────────────────┘"+
			.Reset,
		(strconv.Itoa(int(.handlersCount)), 14), (, 12),
		(, 14), (strconv.Itoa(os.Getpid()), 14),
	)

	var  string
	if .config.Prefork {
		var  string
		 += "%s"
		 += " ┌───────────────────────────────────────────────────┐\n%s"
		 += " └───────────────────────────────────────────────────┘"
		 += "%s"

		 := " │ %s%s%s │"

		// Turn the `pids` variable (in the form ",a,b,c,d,e,f,etc") into a slice of PIDs
		var  []string
		for ,  := range strings.Split(, ",") {
			if  != "" {
				 = append(, )
			}
		}

		var  []string
		 := "Child PIDs ... "
		var  []string

		const  = 49

		 := func() {
			 = append(,
				fmt.Sprintf(
					,
					.Black,
					+.Cyan+(strings.Join(, ", "), -len()),
					.Black,
				),
			)
		}

		for ,  := range  {
			if len(+strings.Join(append(, ), ", ")) >  {
				()
				 = ""
				 = []string{}
			} else {
				 = append(, )
			}
		}

		// Add left over items to their own line
		if len() != 0 {
			()
		}

		// Form logo
		 = fmt.Sprintf(,
			.Black,
			strings.Join(, "\n")+"\n",
			.Reset,
		)
	}

	// Combine both the child PID logo and the main Fiber logo

	// Pad the shorter logo to the length of the longer one
	 := strings.Split(, "\n")
	 := strings.Split(, "\n")

	 := len()
	 := len()

	if  >  {
		 :=  - 
		for  := 0;  < ; ++ {
			 = append(, "")
		}
	} else {
		 :=  - 
		for  := 0;  < ; ++ {
			 = append(, "")
		}
	}

	// Combine the two logos, line by line
	 := "\n"
	for  := range  {
		 += .Black + [] + " " + [] + "\n"
	}

	 := colorable.NewColorableStdout()
	if os.Getenv("TERM") == "dumb" || os.Getenv("NO_COLOR") == "1" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) {
		 = colorable.NewNonColorable(os.Stdout)
	}

	_, _ = fmt.Fprintln(, )
}

// printRoutesMessage print all routes with method, path, name and handlers
// in a format of table, like this:
// method | path | name      | handlers
// GET    | /    | routeName | github.com/gofiber/fiber/v2.emptyHandler
// HEAD   | /    |           | github.com/gofiber/fiber/v2.emptyHandler
func ( *App) () {
	// ignore child processes
	if IsChild() {
		return
	}

	// Alias colors
	 := .config.ColorScheme

	var  []RouteMessage
	for ,  := range .stack {
		for ,  := range  {
			var  RouteMessage
			.name = .Name
			.method = .Method
			.path = .Path
			for ,  := range .Handlers {
				.handlers += runtime.FuncForPC(reflect.ValueOf().Pointer()).Name() + " "
			}
			 = append(, )
		}
	}

	 := colorable.NewColorableStdout()
	if os.Getenv("TERM") == "dumb" || os.Getenv("NO_COLOR") == "1" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) {
		 = colorable.NewNonColorable(os.Stdout)
	}

	 := tabwriter.NewWriter(, 1, 1, 1, ' ', 0)
	// Sort routes by path
	sort.Slice(, func(,  int) bool {
		return [].path < [].path
	})

	_, _ = fmt.Fprintf(, "%smethod\t%s| %spath\t%s| %sname\t%s| %shandlers\t%s\n", .Blue, .White, .Green, .White, .Cyan, .White, .Yellow, .Reset)
	_, _ = fmt.Fprintf(, "%s------\t%s| %s----\t%s| %s----\t%s| %s--------\t%s\n", .Blue, .White, .Green, .White, .Cyan, .White, .Yellow, .Reset)
	for ,  := range  {
		_, _ = fmt.Fprintf(, "%s%s\t%s| %s%s\t%s| %s%s\t%s| %s%s%s\n", .Blue, .method, .White, .Green, .path, .White, .Cyan, .name, .White, .Yellow, .handlers, .Reset)
	}

	_ = .Flush() //nolint:errcheck // It is fine to ignore the error here
}