package main

import (
	"context"
	"os"
	"os/signal"
	"syscall"

	configViper "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/config"
	"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
	control "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/ir"
	"github.com/spf13/viper"
	"go.uber.org/zap"
)

func newConfig() (*viper.Viper, error) {
	var err error
	dv := viper.New()

	defaultConfiguration(dv)

	_, err = configViper.CreateViper(configViper.WithConfigFile(*configFile),
		configViper.WithConfigDir(*configDir), configViper.WithEnvPrefix(EnvPrefix),
		configViper.WithViper(dv))
	if err != nil {
		return nil, err
	}

	return dv, err
}

func reloadConfig() error {
	err := configViper.ReloadViper(configViper.WithConfigFile(*configFile),
		configViper.WithConfigDir(*configDir), configViper.WithEnvPrefix(EnvPrefix),
		configViper.WithViper(cfg))
	if err != nil {
		return err
	}
	cmode.Store(cfg.GetBool("node.kludge_compatibility_mode"))
	audit.Store(cfg.GetBool("audit.enabled"))
	err = logPrm.SetLevelString(cfg.GetString("logger.level"))
	if err != nil {
		return err
	}
	logPrm.PrependTimestamp = cfg.GetBool("logger.timestamp")

	return logPrm.Reload()
}

func watchForSignal(ctx context.Context, cancel func()) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)

	sighupCh := make(chan os.Signal, 1)
	signal.Notify(sighupCh, syscall.SIGHUP)

	for {
		select {
		// signals causing application to shut down should have priority over
		// reconfiguration signal
		case <-ch:
			log.Info(ctx, logs.FrostFSNodeTerminationSignalHasBeenReceivedStopping)
			cancel()
			shutdown(ctx)
			log.Info(ctx, logs.FrostFSNodeTerminationSignalProcessingIsComplete)
			return
		case err := <-intErr: // internal application error
			log.Info(ctx, logs.FrostFSIRInternalError, zap.String("msg", err.Error()))
			cancel()
			shutdown(ctx)
			return
		default:
			// block until any signal is receieved
			select {
			case <-ch:
				log.Info(ctx, logs.FrostFSNodeTerminationSignalHasBeenReceivedStopping)
				cancel()
				shutdown(ctx)
				log.Info(ctx, logs.FrostFSNodeTerminationSignalProcessingIsComplete)
				return
			case err := <-intErr: // internal application error
				log.Info(ctx, logs.FrostFSIRInternalError, zap.String("msg", err.Error()))
				cancel()
				shutdown(ctx)
				return
			case <-sighupCh:
				log.Info(ctx, logs.FrostFSNodeSIGHUPHasBeenReceivedRereadingConfiguration)
				if !innerRing.CompareAndSwapHealthStatus(ctx, control.HealthStatus_READY, control.HealthStatus_RECONFIGURING) {
					log.Info(ctx, logs.FrostFSNodeSIGHUPSkip)
					break
				}
				err := reloadConfig()
				if err != nil {
					log.Error(ctx, logs.FrostFSNodeConfigurationReading, zap.Error(err))
				}
				pprofCmp.reload(ctx)
				metricsCmp.reload(ctx)
				log.Info(ctx, logs.FrostFSIRReloadExtraWallets)
				err = innerRing.SetExtraWallets(cfg)
				if err != nil {
					log.Error(ctx, logs.FrostFSNodeConfigurationReading, zap.Error(err))
				}
				innerRing.CompareAndSwapHealthStatus(ctx, control.HealthStatus_RECONFIGURING, control.HealthStatus_READY)
				log.Info(ctx, logs.FrostFSNodeConfigurationHasBeenReloadedSuccessfully)
			}
		}
	}
}