package hostsfile

import (
	"errors"
	"fmt"
	"net"
	"os"
	"runtime"
	"strings"

	fileutil "github.com/projectdiscovery/utils/file"
)

const (
	localhostName = "localhost"
)

var (
	// MaxLines defines the maximum number of lines the Parse function will process from the hosts file.
	MaxLines = 4096
)

func Path() string {
	if isWindows() {
		return fmt.Sprintf(`%s\System32\Drivers\etc\hosts`, os.Getenv("SystemRoot"))
	}
	return "/etc/hosts"
}

func ParseDefault() (map[string][]string, error) {
	return Parse(Path())
}

func Parse(p string) (map[string][]string, error) {
	if !fileutil.FileExists(p) {
		return nil, errors.New("hosts file doesn't exist")
	}

	hostsFileCh, err := fileutil.ReadFile(p)
	if err != nil {
		return nil, err
	}

	items := make(map[string][]string)
	lineCount := 0

	for line := range hostsFileCh {
		lineCount++
		if lineCount > MaxLines {
			break
		}

		line = strings.TrimSpace(line)
		// skip comments and empty lines
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		// discard comment part
		if idx := strings.Index(line, "#"); idx > 0 {
			line = line[:idx]
		}
		tokens := strings.Fields(line)
		if len(tokens) > 1 {
			ip := tokens[0]
			for _, hostname := range tokens[1:] {
				items[hostname] = append(items[hostname], ip)
			}
		}
	}

	// windows 11 resolves localhost with system dns resolver
	if _, ok := items[localhostName]; !ok && isWindows() {
		localhostIPs, err := net.LookupHost(localhostName)
		if err != nil {
			return nil, err
		}
		items[localhostName] = localhostIPs
	}

	return items, nil
}

func isWindows() bool {
	return runtime.GOOS == "windows"
}
