// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package power

import (
	"context"
	"errors"
	"fmt"
	"net"
	"regexp"
	"time"
)

var (
	macAddrRegex = regexp.MustCompile(`(?i)^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$`)
	// Magic Packet header is 0xFF repeated 6 times.
	magicPacketHeader = []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
)

const (
	magicPacketLength = 102

	// Controller machines use 192.168.42.1/24 for swarming bots
	// This will broadcast to that entire subnet.
	botBroadcastAddr = "192.168.42.255:9"

	// Controller machines have multiple interfaces, currently
	// 'eno2' is used for swarming bots.
	botInterface = "eno2"
)

// Reboot sends a WakeOnLAN magic packet {magicPacketHeader + macAddr x 16}
// using the specified network interface to the broadcast address
func WOLReboot(broadcastAddr, interfaceName, macAddr string) error {
	if !macAddrRegex.Match([]byte(macAddr)) {
		return fmt.Errorf("Invalid MAC: %s", macAddr)
	}

	remoteHwAddr, err := net.ParseMAC(macAddr)
	if err != nil {
		return err
	}

	localAddr, err := getUDPAddrFromIFace(interfaceName)
	if err != nil {
		return err
	}
	remoteAddr, err := net.ResolveUDPAddr("udp", broadcastAddr)
	if err != nil {
		return err
	}

	return sendMagicPacket(localAddr, remoteAddr, remoteHwAddr)
}

func getUDPAddrFromIFace(ifaceName string) (*net.UDPAddr, error) {
	iface, err := net.InterfaceByName(ifaceName)
	if err != nil {
		return nil, err
	}

	addrs, err := iface.Addrs()
	if err != nil {
		return nil, err
	}

	for _, addr := range addrs {
		if ipAddr, ok := addr.(*net.IPNet); ok {
			// Need an IPv4, non-loopback address to send on
			if !ipAddr.IP.IsLoopback() && ipAddr.IP.To4() != nil {
				return &net.UDPAddr{
					IP: ipAddr.IP,
				}, nil
			}
		}
	}

	return nil, errors.New("No UDPAddr found on interface")
}

func sendMagicPacket(localAddr, remoteAddr *net.UDPAddr, remoteHwAddr net.HardwareAddr) error {
	packet := magicPacketHeader
	for i := 0; i < 16; i++ {
		packet = append(packet, remoteHwAddr...)
	}

	if len(packet) != magicPacketLength {
		return fmt.Errorf("Wake-On-LAN packet incorrect length: %d", len(packet))
	}

	conn, err := net.DialUDP("udp", localAddr, remoteAddr)
	if err != nil {
		return err
	}
	defer conn.Close()

	// Attempt to send the Magic Packet TEN times in a row.  The UDP packet sometimes
	// does not make it to the DUT and this is the simplest way to increase the chance
	// the device reboots.
	for i := 0; i < 10; i++ {
		n, err := conn.Write(packet)

		if n != magicPacketLength {
			return errors.New("Failed to send correct Wake-On-LAN packet length")
		}

		if err != nil {
			return err
		}
		time.Sleep(1 * time.Second)
	}

	return nil
}

type WOLPowerManager struct {
	botBroadcastAddr string
	botInterface     string
	mac              string
}

func NewWOLPowerManager(mac string) *WOLPowerManager {
	return &WOLPowerManager{
		botBroadcastAddr: botBroadcastAddr,
		botInterface:     botInterface,
		mac:              mac,
	}
}

func (w *WOLPowerManager) Powercycle(ctx context.Context) error {
	return WOLReboot(w.botBroadcastAddr, w.botInterface, w.mac)
}
