package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"

	"github.com/pingcap/log"
	"github.com/tidbcloud/tiinf/monitor/titracing"
	"go.uber.org/zap"
)

const (
	serviceName = "cluster-agent"
)

func main() {
	os.Exit(run())
}

func run() int {
	// init config
	err := InitConfig(os.Args[1:])
	if err != nil {
		if errors.Is(err, flag.ErrHelp) {
			return 0
		}
		panic(err)
	}
	cfg := GetConfig()

	// init logger, use pingcap/log now
	logger, props, err := log.InitLogger(&log.Config{Level: cfg.LogLevel})
	if err != nil {
		panic(err)
	}
	log.ReplaceGlobals(logger, props)
	log.Info("Starting cluster-agent server...")
	defer log.Sync() //nolint:errcheck // Sync error at shutdown is not critical

	auditManager, err := newAuditManager(cfg)
	if err != nil {
		panic(fmt.Sprintf("failed to create audit manager: %v", err))
	}
	defer func() {
		if closeErr := auditManager.Close(); closeErr != nil {
			log.Error("failed to close audit manager", zap.Error(closeErr))
		}
	}()

	// Create context that listens for the interrupt signal from the OS.
	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	// init tracing even if the tracing is currently not usable in regional, because we need to init Propagator
	// to extra some info from HTTP header.
	if _, err = titracing.InitJaeger(serviceName); err != nil {
		log.Error("init tiinf jaeger provider failed", zap.Error(err))
	}
	var wg sync.WaitGroup

	// Build the shared AgentService before launching goroutines so both the
	// internal gRPC server and the HTTP gateway use the same instance.
	agentSvc := buildAgentService(ctx, cfg)

	// Deactivate any privileged TiDB stuck in SYSTEM keyspace from a previous
	// agent instance whose deactivation goroutine was lost on restart.
	agentSvc.RecoverPrivilegedTiDBOnStartup(ctx)

	wg.Add(1)
	go func() {
		defer wg.Done()
		setupAndRunGRPCServer(ctx, cfg, agentSvc)
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		setupAndRunGRPCGateway(ctx, cfg, agentSvc, auditManager)
	}()

	wg.Wait()
	log.Info("cluster-agent server stopped")

	return 0
}
