package sing

import (
	"bytes"
	"github.com/InazumaV/V2bX/api/panel"
	"github.com/goccy/go-json"
	log "github.com/sirupsen/logrus"
	"os"
	"strings"
)

func updateDNSConfig(node *panel.NodeInfo) (err error) {
	dnsPath := os.Getenv("SING_DNS_PATH")
	if len(node.RawDNS.DNSJson) != 0 {
		var prettyJSON bytes.Buffer
		if err := json.Indent(&prettyJSON, node.RawDNS.DNSJson, "", " "); err != nil {
			return err
		}
		err = saveDnsConfig(prettyJSON.Bytes(), dnsPath)
	} else if len(node.RawDNS.DNSMap) != 0 {
		dnsConfig := DNSConfig{
			Servers: []map[string]interface{}{
				{
					"tag":     "default",
					"address": "https://8.8.8.8/dns-query",
					"detour":  "direct",
				},
			},
		}
		for id, value := range node.RawDNS.DNSMap {
			dnsConfig.Servers = append(dnsConfig.Servers,
				map[string]interface{}{
					"tag":              id,
					"address":          value["address"],
					"address_resolver": "default",
					"detour":           "direct",
				},
			)
			rule := map[string]interface{}{
				"server":        id,
				"disable_cache": true,
			}
			for _, ruleType := range []string{"domain_suffix", "domain_keyword", "domain_regex", "geosite"} {
				var domains []string
				for _, v := range value["domains"].([]string) {
					split := strings.SplitN(v, ":", 2)
					prefix := strings.ToLower(split[0])
					if prefix == ruleType || (prefix == "domain" && ruleType == "domain_suffix") {
						if len(split) > 1 {
							domains = append(domains, split[1])
						}
						if len(domains) > 0 {
							rule[ruleType] = domains
						}
					}
				}
			}
			dnsConfig.Rules = append(dnsConfig.Rules, rule)
		}
		dnsConfigJSON, err := json.MarshalIndent(dnsConfig, "", "  ")
		if err != nil {
			log.WithField("err", err).Error("Error marshaling dnsConfig to JSON")
			return err
		}
		err = saveDnsConfig(dnsConfigJSON, dnsPath)
	}
	return err
}

func saveDnsConfig(dns []byte, dnsPath string) (err error) {
	currentData, err := os.ReadFile(dnsPath)
	if err != nil {
		log.WithField("err", err).Error("Failed to read SING_DNS_PATH")
		return err
	}
	if !bytes.Equal(currentData, dns) {
		if err = os.Truncate(dnsPath, 0); err != nil {
			log.WithField("err", err).Error("Failed to clear SING DNS PATH file")
		}
		if err = os.WriteFile(dnsPath, dns, 0644); err != nil {
			log.WithField("err", err).Error("Failed to write DNS to SING DNS PATH file")
		}
	}
	return err
}