package cli

import (
	"context"
	"errors"
	"time"

	"github.com/kardianos/service"
	"github.com/spf13/cobra"
)

// Restart implements the logic from cmdRestart.Run
func (sc *ServiceCommand) Restart(cmd *cobra.Command, args []string) error {
	logger := mainLog.Load()
	logger.Debug().Msg("Service restart command started")

	readConfig(false)
	v.Unmarshal(&cfg)
	cdUID = curCdUID()
	cdMode := cdUID != ""

	s, p, err := sc.initializeServiceManager()
	if err != nil {
		logger.Error().Err(err).Msg("Failed to initialize service manager")
		return err
	}

	if _, err := s.Status(); errors.Is(err, service.ErrNotInstalled) {
		logger.Warn().Msg("Service not installed")
		return nil
	}

	p.cfg = &cfg
	if iface == "" {
		iface = autoIface
	}
	p.preRun()
	if ir := runningIface(s); ir != nil {
		p.runningIface = ir.Name
		p.requiredMultiNICsConfig = ir.All
	}

	initInteractiveLogging()

	var validateConfigErr error
	if cdMode {
		logger.Debug().Msg("Validating ControlD remote config")
		validateConfigErr = doValidateCdRemoteConfig(cdUID, false)
		if validateConfigErr != nil {
			logger.Warn().Err(validateConfigErr).Msg("ControlD remote config validation failed")
		}
	}

	if ir := runningIface(s); ir != nil {
		iface = ir.Name
	}

	doRestart := func() bool {
		logger.Debug().Msg("Starting service restart sequence")

		tasks := []task{
			{s.Stop, true, "Stop"},
			{func() error {
				// restore static DNS settings or DHCP
				p.resetDNS(false, true)
				return nil
			}, false, "Cleanup"},
			{func() error {
				time.Sleep(time.Second * 1)
				return nil
			}, false, "Waiting for service to stop"},
		}
		if !doTasks(tasks) {
			logger.Error().Msg("Service stop tasks failed")
			return false
		}
		tasks = []task{
			{s.Start, true, "Start"},
		}
		success := doTasks(tasks)
		if success {
			logger.Debug().Msg("Service restart sequence completed successfully")
		} else {
			logger.Error().Msg("Service restart sequence failed")
		}
		return success
	}

	if doRestart() {
		if dir, err := socketDir(); err == nil {
			timeout := dialSocketControlServerTimeout
			if validateConfigErr != nil {
				timeout = 5 * time.Second
			}
			if cc := newSocketControlClientWithTimeout(context.TODO(), s, dir, timeout); cc != nil {
				_, _ = cc.post(ifacePath, nil)
				logger.Debug().Msg("Control server ping successful")
			} else {
				logger.Warn().Err(err).Msg("Service was restarted, but ctrld process may not be ready yet")
			}
		} else {
			logger.Warn().Err(err).Msg("Service was restarted, but could not ping the control server")
		}
		logger.Notice().Msg("Service restarted")
	} else {
		logger.Error().Msg("Service restart failed")
	}

	logger.Debug().Msg("Service restart command completed")
	return nil
}
