package wol

import (
	"bytes"
	"encoding/hex"
	"errors"
	"fmt"
	"net"
	"regexp"
	"strings"
)

var (
	MacFormatError = errors.New("mac 地址格式错误")
)

type Service struct {
}

var Services *Service

func init() {
	Services = &Service{}
}

func (s *Service) validateMac(mac string) bool {
	exp, _ := regexp.Compile("([0-9a-fA-F]{2}(-|:)?){5}([a-fA-F0-9]{2})")

	macLen := len(mac)

	return exp.MatchString(mac) && (macLen == 12 || macLen == 17)
}

func (s *Service) WakeUp(mac string, port int) error {
	mac = strings.Replace(strings.Replace(mac, ":", "", -1), "-", "", -1)
	if !s.validateMac(mac) {
		return MacFormatError
	}

	return s.wake(mac, port)
}

func (s *Service) wake(mac string, port int) error {
	udpAddr, _ := net.ResolveUDPAddr("udp", fmt.Sprintf("255.255.255.255:%d", port))
	interfaces, err := net.Interfaces()

	if err != nil {
		return err
	}

	macHex, _ := hex.DecodeString(mac)
	// 广播MAC地址 FF:FF:FF:FF:FF:FF
	var broadcast = []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
	var buffer bytes.Buffer
	buffer.Write(broadcast)
	for i := 0; i < 16; i++ {
		buffer.Write(macHex)
	}
	wolPackage := buffer.Bytes()

	for _, i := range interfaces {
		if i.Flags&net.FlagUp == 0 {
			continue
		}

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

		for _, addr := range addrs {
			if ip, ok := addr.(*net.IPNet); ok {
				if ipv4 := ip.IP.To4(); ipv4 != nil {
					conn, err := net.DialUDP("udp", &net.UDPAddr{IP: ipv4}, udpAddr)

					if err != nil {
						return err
					}
					_, _ = conn.Write(wolPackage)
					_ = conn.Close()
				}
			}
		}
	}

	return err
}
