package network

import (
	"fmt"
	"os/exec"
	"strings"
)

// IfDown brings an interface down via ifdown (or ip link set down as fallback).
func IfDown(name string) error {
	out, err := exec.Command("ifdown", "--force", name).CombinedOutput()
	if err != nil {
		// fallback: ip link set down
		out2, err2 := exec.Command("ip", "link", "set", name, "down").CombinedOutput()
		if err2 != nil {
			return fmt.Errorf("ifdown %s: %s\nip fallback: %s", name, strings.TrimSpace(string(out)), strings.TrimSpace(string(out2)))
		}
	}
	return nil
}

// IfUp brings an interface up via ifup (or ip link set up as fallback).
func IfUp(name string) error {
	out, err := exec.Command("ifup", name).CombinedOutput()
	if err != nil {
		out2, err2 := exec.Command("ip", "link", "set", name, "up").CombinedOutput()
		if err2 != nil {
			return fmt.Errorf("ifup %s: %s\nip fallback: %s", name, strings.TrimSpace(string(out)), strings.TrimSpace(string(out2)))
		}
	}
	return nil
}

// IfRestart brings an interface down then up.
func IfRestart(name string) error {
	_ = IfDown(name) // ignore "already down" errors
	return IfUp(name)
}

// ApplyPending merges pending configs into /etc/network/interfaces,
// writes the file, and restarts affected interfaces.
// Returns a per-interface error map (nil key = write error).
func ApplyPending() map[string]error {
	errs := map[string]error{}

	pending := GetAllPending()
	if len(pending) == 0 {
		return errs
	}

	// Read current file config
	configs, err := ParseConfig()
	if err != nil {
		errs["__parse__"] = err
		return errs
	}

	// Merge
	for name, cfg := range pending {
		configs[name] = cfg
	}

	// Write file
	if err := WriteConfig(configs); err != nil {
		errs["__write__"] = err
		return errs
	}

	// Restart each changed interface
	for name := range pending {
		if name == "lo" {
			ClearPendingConfig(name)
			continue
		}
		// For VLAN interfaces ensure the kernel interface exists before ifup.
		if IsVLAN(name) {
			if err := EnsureVLANExists(name); err != nil {
				errs[name] = err
				continue
			}
		}
		_ = IfDown(name)
		if cfg := configs[name]; cfg != nil && cfg.Auto {
			if err := IfUp(name); err != nil {
				errs[name] = err
				continue
			}
		}
		ClearPendingConfig(name)
	}

	return errs
}
