package main

import (
	"flag"
	"fmt"
	"git.e3t.cc/e3team/pancheri"
	"github.com/miekg/dns"
	"github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"
	"os"
)

func main() {
	configPath := flag.String("config", "/etc/pancheri/config.yml", "Path to enter a file or directory to load configuration from")
	printUsage := flag.Bool("help", false, "Print command line usage")

	flag.Parse()

	if *printUsage {
		flag.Usage()
		os.Exit(0)
	}

	c, err := pancheri.LoadConfig(*configPath)

	if err != nil {
		fmt.Printf("failed to load config: %s", err)
	}

	if c.Logging.Format == "json" {
		logrus.SetFormatter(&logrus.JSONFormatter{})
	}
	logrus.SetLevel(c.Logging.Level)

	zones := make(map[string]*pancheri.Zone, len(c.Zone.LoadFiles))

	for _, zonefile := range c.Zone.LoadFiles {
		logrus.WithFields(logrus.Fields{
			"file": zonefile,
		}).Info("loading zone")
		zone, err := pancheri.LoadZone(zonefile)
		if err != nil {
			logrus.Errorf("failed to load zone %s: %s", zonefile, err)
			os.Exit(1)
		}
		authoritativeZone := "." + zone.Root + "."
		logrus.WithFields(logrus.Fields{
			"rsha": zone.ReducedHash,
			"root": authoritativeZone,
		}).Info("zone loaded")
		zones[authoritativeZone] = zone
	}

	logrus.WithFields(logrus.Fields{
		"port": "2112",
	}).Info("starting promhttp listener")

	go func() {
		err := pancheri.PromMain()
		if err != nil {
			logrus.Errorf("error in prom listener: %s", err)
			os.Exit(1)
		}
	}()

	logrus.WithFields(logrus.Fields{
		"host": c.Server.Host,
		"port": c.Server.Port,
	}).Info("starting DNS listener")

	var r *pancheri.Resolver

	if c.Resolver.Enable {
		logrus.WithFields(logrus.Fields{
			"upstream": c.Resolver.Upstream,
		}).Info("enabling upstream resolver")

		r = pancheri.NewResolver(c.Resolver.Upstream)
	}

	var b *pancheri.Blackholer

	if c.Blackhole.Enable {
		logrus.WithFields(logrus.Fields{
			"denyfiles": len(c.Blackhole.BlockLists),
		}).Info("enabling blackholer")

		b = &pancheri.Blackholer{
			DenyDomains: []string{},
		}

		for _, file := range c.Blackhole.BlockLists {
			logrus.WithFields(logrus.Fields{
				"file": file,
			}).Info("loading blocklist")

			f, err := os.Open(file)
			if err != nil {
				logrus.Errorf("error loading blocklist file: %s", err)
			}

			var cfg pancheri.BlackholeFile
			decoder := yaml.NewDecoder(f)

			err = decoder.Decode(&cfg)
			if err != nil {
				logrus.Errorf("error decoding blocklist file: %s", err)
			}

			err = f.Close()
			if err != nil {
				logrus.Errorf("error closing blocklist file: %s", err)
			}

			b.DenyDomains = append(b.DenyDomains, cfg.DenyDomains...)
			logrus.WithFields(logrus.Fields{
				"file": file,
			}).Infof("loaded %d hosts", len(cfg.DenyDomains))

			if !b.ShouldBlock("eu1.clevertap-prod.com") {
				logrus.Errorf("failed sanity check!")
			}
		}

		logrus.WithFields(logrus.Fields{
			"hosts": len(b.DenyDomains),
		}).Info("blackhole enabled")
	}

	handler := pancheri.Handler{
		C: c,
		R: r,
		A: &pancheri.Authority{
			Zones: zones,
		},
		B: b,
	}
	server := &dns.Server{
		Addr:      c.Server.Host + ":" + c.Server.Port,
		Net:       "udp",
		Handler:   &handler,
		UDPSize:   65535,
		ReusePort: true,
	}
	err = server.ListenAndServe()

	if err != nil {
		logrus.Errorf("failed to start server: %s", err)
		os.Exit(1)
	}
}