package service

import (
	"context"
	"fmt"
	"time"
)

func (s *Service) Stop() (err error) {
	s.startStopMutex.Lock()
	defer s.startStopMutex.Unlock()

	s.portMutex.RLock()
	serviceNotRunning := len(s.ports) == 0
	s.portMutex.RUnlock()
	if serviceNotRunning {
		// TODO replace with goservices.ErrAlreadyStopped
		return nil
	}

	s.logger.Info("stopping")

	s.keepPortCancel()
	<-s.keepPortDoneCh

	return s.cleanup()
}

func (s *Service) cleanup() (err error) {
	s.portMutex.Lock()
	defer s.portMutex.Unlock()

	if s.settings.DownCommand != "" {
		const downTimeout = 60 * time.Second
		ctx, cancel := context.WithTimeout(context.Background(), downTimeout)
		defer cancel()
		err = runCommand(ctx, s.cmder, s.logger, s.settings.DownCommand, s.ports)
		if err != nil {
			err = fmt.Errorf("running down command: %w", err)
			s.logger.Error(err.Error())
		}
	}

	for _, port := range s.ports {
		err = s.portAllower.RemoveAllowedPort(context.Background(), port)
		if err != nil {
			return fmt.Errorf("blocking previous port in firewall: %w", err)
		}

		if s.settings.ListeningPort != 0 {
			ctx := context.Background()
			const listeningPort = 0 // 0 to clear the redirection
			err = s.portAllower.RedirectPort(ctx, s.settings.Interface, port, listeningPort)
			if err != nil {
				return fmt.Errorf("removing previous port redirection in firewall: %w", err)
			}
		}
	}

	s.ports = nil

	filepath := s.settings.Filepath
	s.logger.Info("clearing port file " + filepath)
	err = s.writePortForwardedFile(nil)
	if err != nil {
		return fmt.Errorf("clearing port file: %w", err)
	}

	return nil
}
