package app

import (
	"easyaudioencode/internal/core/host"
	"fmt"
	"log/slog"
	"net"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"syscall"

	"easyaudioencode/internal/conf"

	"git.lnton.com/lnton/pkg/logger"
	"git.lnton.com/lnton/pkg/server"
	"git.lnton.com/lnton/pkg/system"
)

func Run(bc *conf.Bootstrap) {
	// 以可执行文件所在目录为工作目录，防止以服务方式运行时，工作目录切换到其它位置
	bin, _ := os.Executable()
	if err := os.Chdir(filepath.Dir(bin)); err != nil {
		slog.Error("change work dir fail", "err", err)
	}

	log, clean := SetupLog(bc)
	defer clean()

	handler, cleanUp, err := WireApp(bc, log)
	if err != nil {
		slog.Error("程序构建失败", "err", err.Error())
		panic(err)
	}
	defer cleanUp()

	var svc *server.Server
	if bc.Server.HTTP.Port != 0 {
		svc = server.New(handler,
			server.Port(strconv.Itoa(bc.Server.HTTP.Port)),
			server.ReadTimeout(bc.Server.HTTP.Timeout.Duration()),
			server.WriteTimeout(bc.Server.HTTP.Timeout.Duration()),
		)
		host.StartOk <- struct{}{} // http端口已监听,开始心跳保活
		go svc.Start()
	} else {
		svc = server.New(handler,
			server.ReadTimeout(bc.Server.HTTP.Timeout.Duration()),
			server.WriteTimeout(bc.Server.HTTP.Timeout.Duration()),
		)
		lis, err := net.Listen("tcp", ":0")
		if err != nil {
			fmt.Printf("创建监听器失败: %v\n", err)
			return
		}
		//bc.Server.HTTP.Port = lis.Addr().(*net.TCPAddr).Port
		bc.Server.HTTP.Port = lis.Addr().(*net.TCPAddr).Port
		host.StartOk <- struct{}{} // http端口已监听,开始心跳保活
		go svc.StartWithListen(lis)
	}

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
	fmt.Println("服务启动成功 port:", bc.Server.HTTP.Port)

	select {
	case s := <-interrupt:
		slog.Info(`<-interrupt`, "signal", s.String())
	case err := <-svc.Notify():
		system.ErrPrintf("err: %s\n", err.Error())
		slog.Error(`<-server.Notify()`, "err", err)
	}
	if err := svc.Shutdown(); err != nil {
		slog.Error(`server.Shutdown()`, "err", err)
	}
}

// SetupLog 初始化日志
func SetupLog(bc *conf.Bootstrap) (*slog.Logger, func()) {
	logDir := filepath.Join(system.Getwd(), bc.Log.Dir)
	return logger.SetupSlog(logger.Config{
		Dir:          logDir,                            // 日志地址
		Debug:        bc.Debug,                          // 服务级别Debug/Release
		MaxAge:       bc.Log.MaxAge.Duration(),          // 日志存储时间
		RotationTime: bc.Log.RotationTime.Duration(),    // 循环时间
		RotationSize: bc.Log.RotationSize * 1024 * 1024, // 循环大小
		Level:        bc.Log.Level,                      // 日志级别
	})
}
