//go:build (linux && !android) || freebsd

package dns

import (
	"errors"
	"fmt"
	"io/fs"
	"net/netip"
	"os"
	"path/filepath"
	"strings"

	log "github.com/sirupsen/logrus"
)

func CheckUncleanShutdown(wgIface string) error {
	if _, err := os.Stat(fileUncleanShutdownResolvConfLocation); err != nil {
		if errors.Is(err, fs.ErrNotExist) {
			// no file -> clean shutdown
			return nil
		} else {
			return fmt.Errorf("state: %w", err)
		}
	}

	log.Warnf("detected unclean shutdown, file %s exists", fileUncleanShutdownResolvConfLocation)

	managerData, err := os.ReadFile(fileUncleanShutdownManagerTypeLocation)
	if err != nil {
		return fmt.Errorf("read %s: %w", fileUncleanShutdownManagerTypeLocation, err)
	}

	managerFields := strings.Split(string(managerData), ",")
	if len(managerFields) < 2 {
		return errors.New("split manager data: insufficient number of fields")
	}
	osManagerTypeStr, dnsAddressStr := managerFields[0], managerFields[1]

	dnsAddress, err := netip.ParseAddr(dnsAddressStr)
	if err != nil {
		return fmt.Errorf("parse dns address %s failed: %w", dnsAddressStr, err)
	}

	log.Warnf("restoring unclean shutdown dns settings via previously detected manager: %s", osManagerTypeStr)

	// determine os manager type, so we can invoke the respective restore action
	osManagerType, err := newOsManagerType(osManagerTypeStr)
	if err != nil {
		return fmt.Errorf("detect previous host manager: %w", err)
	}

	manager, err := newHostManagerFromType(wgIface, osManagerType)
	if err != nil {
		return fmt.Errorf("create previous host manager: %w", err)
	}

	if err := manager.restoreUncleanShutdownDNS(&dnsAddress); err != nil {
		return fmt.Errorf("restore unclean shutdown backup: %w", err)
	}

	return nil
}

func createUncleanShutdownIndicator(sourcePath string, managerType osManagerType, dnsAddress string) error {
	dir := filepath.Dir(fileUncleanShutdownResolvConfLocation)
	if err := os.MkdirAll(dir, os.FileMode(0755)); err != nil {
		return fmt.Errorf("create dir %s: %w", dir, err)
	}

	if err := copyFile(sourcePath, fileUncleanShutdownResolvConfLocation); err != nil {
		return fmt.Errorf("create %s: %w", sourcePath, err)
	}

	managerData := fmt.Sprintf("%s,%s", managerType, dnsAddress)

	if err := os.WriteFile(fileUncleanShutdownManagerTypeLocation, []byte(managerData), 0644); err != nil { //nolint:gosec
		return fmt.Errorf("create %s: %w", fileUncleanShutdownManagerTypeLocation, err)
	}
	return nil
}

func removeUncleanShutdownIndicator() error {
	if err := os.Remove(fileUncleanShutdownResolvConfLocation); err != nil && !errors.Is(err, fs.ErrNotExist) {
		return fmt.Errorf("remove %s: %w", fileUncleanShutdownResolvConfLocation, err)
	}
	if err := os.Remove(fileUncleanShutdownManagerTypeLocation); err != nil && !errors.Is(err, fs.ErrNotExist) {
		return fmt.Errorf("remove %s: %w", fileUncleanShutdownManagerTypeLocation, err)
	}
	return nil
}
