package host

import (
	"net"
	"os"

	"git.giaever.org/joachimmg/go-log.git/log"
	"git.giaever.org/joachimmg/m-dns/errors"
)

type IPvType int

const (
	IPv4 IPvType = iota << 1
	IPv6 IPvType = iota << 1
	NoIP IPvType = iota << 1
)

type HostIP interface {
	String() string
	Type() (net.IP, IPvType)
	AsIP() net.IP
}

type IP net.IP

func (i IP) String() string {
	return i.AsIP().String()
}

func (i IP) AsIP() net.IP {
	return net.IP(i)
}

func (i IP) Type() (net.IP, IPvType) {
	if ip := i.AsIP().To4(); ip != nil {
		switch ip.String() {
		case "127.0.0.1",
			net.IPv4zero.String(),
			net.IPv4bcast.String(),
			net.IPv4allsys.String(),
			net.IPv4allrouter.String():
			return nil, NoIP
		default:
			return ip, IPv4
		}
	}

	if ip := i.AsIP().To16(); ip != nil {
		switch ip.String() {
		case net.IPv6zero.String(),
			net.IPv6loopback.String(),
			net.IPv6unspecified.String(),
			net.IPv6linklocalallnodes.String(),
			net.IPv6linklocalallrouters.String(),
			net.IPv6interfacelocalallnodes.String():
			return nil, NoIP
		default:
			return ip, IPv6
		}
	}

	return nil, NoIP
}

func (i IP) validForHostname(hn HostString) (IP, error) {
	log.Traceln(errors.HostIP, i, hn)

	if _, t := i.Type(); t == NoIP {
		log.Traceln(errors.HostIP, errors.HostIPIsInvalid)
		return nil, errors.HostIPIsInvalid
	}

	f := false
	if lhn, _ := os.Hostname(); lhn == hn.String() {
		addrs, err := net.InterfaceAddrs()

		if err != nil {
			log.Traceln(errors.HostIP, err)
			return nil, err
		}

		for _, addr := range addrs {
			if addr.(*net.IPNet).Contains(i.AsIP()) {
				f = true
				break
			}
		}

	} else {
		addrs, err := net.LookupIP(hn.String())

		if err != nil {
			log.Traceln(errors.HostIP, err)
			return nil, err
		}

		for _, addr := range addrs {
			if addr.String() == i.String() {
				f = true
			}
		}
	}

	if f == false {
		log.Traceln(errors.HostIP, errors.HostIPIsInvalid)
		return nil, errors.HostIPIsInvalid
	}

	return i, nil
}
