package wifi

import (
	"net"
	"time"

	"github.com/bettercap/bettercap/v2/network"
)

func (mod *WiFiModule) isInterfaceConnected() bool {
	ifaces, err := net.Interfaces()
	if err != nil {
		mod.Error("error while enumerating interfaces: %s", err)
		return false
	}

	for _, iface := range ifaces {
		if mod.iface.HwAddress == network.NormalizeMac(iface.HardwareAddr.String()) {
			return true
		}
	}

	return false
}

func (mod *WiFiModule) hopUnlocked(channel int) (mustStop bool) {
	// mod.Debug("hopping on channel %d", channel)

	if err := network.SetInterfaceChannel(mod.iface.Name(), channel); err != nil {
		// check if the device has been disconnected
		if mod.isInterfaceConnected() == false {
			mod.Error("interface %s disconnected, stopping module", mod.iface.Name())
			mustStop = true
		} else {
			mod.Warning("error while hopping to channel %d: %s", channel, err)
		}
	}

	mod.State.Store("channel", channel)

	return
}

func (mod *WiFiModule) hop(channel int) (mustStop bool) {
	mod.chanLock.Lock()
	defer mod.chanLock.Unlock()

	return mod.hopUnlocked(channel)
}

func (mod *WiFiModule) onChannel(channel int, cb func()) {
	mod.chanLock.Lock()
	defer mod.chanLock.Unlock()

	prev := mod.stickChan
	mod.stickChan = channel

	mod.hopUnlocked(channel)

	cb()

	mod.stickChan = prev
}

func (mod *WiFiModule) channelHopper() {
	mod.reads.Add(1)
	defer mod.reads.Done()

	mod.Info("channel hopper started.")

	for mod.Running() {
		delay := mod.hopPeriod
		// if we have both 2.4 and 5ghz capabilities, we have
		// more channels, therefore we need to increase the time
		// we hop on each one otherwise me lose information
		if len(mod.frequencies) > 14 {
			delay = delay * 2
		}

		frequencies := mod.frequencies

	loopCurrentChannels:
		for _, frequency := range frequencies {
			channel := network.Dot11Freq2Chan(frequency)
			// stick to the access point channel as long as it's selected
			// or as long as we're deauthing on it
			if mod.stickChan != 0 {
				channel = mod.stickChan
			}

			if stop := mod.hop(channel); stop {
				mod.forcedStop()
				return
			}

			select {
			case <-mod.hopChanges:
				mod.Debug("hop changed")
				break loopCurrentChannels
			case <-time.After(delay):
				if !mod.Running() {
					return
				}
			}
		}
	}
}
