package util

import (
	"log/syslog"
	"os"
	"strings"

	"github.com/Sirupsen/logrus"
	logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
	logrus_logstash "github.com/bshuster-repo/logrus-logstash-hook"
)

var (
	stringFacilityMap = map[string]syslog.Priority{
		"LOG_KERN":     syslog.LOG_KERN,
		"LOG_USER":     syslog.LOG_USER,
		"LOG_MAIL":     syslog.LOG_MAIL,
		"LOG_DAEMON":   syslog.LOG_DAEMON,
		"LOG_AUTH":     syslog.LOG_AUTH,
		"LOG_SYSLOG":   syslog.LOG_SYSLOG,
		"LOG_LPR":      syslog.LOG_LPR,
		"LOG_NEWS":     syslog.LOG_NEWS,
		"LOG_UUCP":     syslog.LOG_UUCP,
		"LOG_CRON":     syslog.LOG_CRON,
		"LOG_AUTHPRIV": syslog.LOG_AUTHPRIV,
		"LOG_FTP":      syslog.LOG_FTP,
		"LOG_LOCAL0":   syslog.LOG_LOCAL0,
		"LOG_LOCAL1":   syslog.LOG_LOCAL1,
		"LOG_LOCAL2":   syslog.LOG_LOCAL2,
		"LOG_LOCAL3":   syslog.LOG_LOCAL3,
		"LOG_LOCAL4":   syslog.LOG_LOCAL4,
		"LOG_LOCAL5":   syslog.LOG_LOCAL5,
		"LOG_LOCAL6":   syslog.LOG_LOCAL6,
		"LOG_LOCAL7":   syslog.LOG_LOCAL7,
	}
	facilityStringMap = map[syslog.Priority]string{
		syslog.LOG_KERN:     "LOG_KERN",
		syslog.LOG_USER:     "LOG_USER",
		syslog.LOG_MAIL:     "LOG_MAIL",
		syslog.LOG_DAEMON:   "LOG_DAEMON",
		syslog.LOG_AUTH:     "LOG_AUTH",
		syslog.LOG_SYSLOG:   "LOG_SYSLOG",
		syslog.LOG_LPR:      "LOG_LPR",
		syslog.LOG_NEWS:     "LOG_NEWS",
		syslog.LOG_UUCP:     "LOG_UUCP",
		syslog.LOG_CRON:     "LOG_CRON",
		syslog.LOG_AUTHPRIV: "LOG_AUTHPRIV",
		syslog.LOG_FTP:      "LOG_FTP",
		syslog.LOG_LOCAL0:   "LOG_LOCAL0",
		syslog.LOG_LOCAL1:   "LOG_LOCAL1",
		syslog.LOG_LOCAL2:   "LOG_LOCAL2",
		syslog.LOG_LOCAL3:   "LOG_LOCAL3",
		syslog.LOG_LOCAL4:   "LOG_LOCAL4",
		syslog.LOG_LOCAL5:   "LOG_LOCAL5",
		syslog.LOG_LOCAL6:   "LOG_LOCAL6",
		syslog.LOG_LOCAL7:   "LOG_LOCAL7",
	}
)

//SyslogConfig config to setup sandstorm logger.
type SyslogConfig struct {
	Enabled  bool
	Host     string
	Priority string
	Facility string
	Tag      string
	Level    string
	Format   string
	File     string
}

//SetupLogging setup a logger
func SetupLogging(config *SyslogConfig) logrus.FieldLogger {
	logger := logrus.New()

	if config.File != "" {
		f, err := os.OpenFile(config.File, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
		if err == nil {
			logger.Out = f
		} else {
			logger.Error(err.Error())
		}
	} else {
		logger.Out = os.Stdout
	}

	if config.Level != "" {
		level, err := logrus.ParseLevel(config.Level)
		if err == nil {
			logger.Level = level
		} else {
			logger.Warnf("unable to parse configured log level %s", err.Error())
			err = nil
		}
	}

	switch config.Format {
	case "json":
		logger.Formatter = &logrus.JSONFormatter{}
	case "logstash":
		logger.Formatter = &logrus_logstash.LogstashFormatter{Type: "sandstorm-server"}
	case "text":
		logger.Formatter = &logrus.TextFormatter{}
	}

	if config.Enabled == false {
		return logger
	}

	logHost := "localhost"
	if config.Host != "" {
		logHost = config.Host
	}

	logFacility := syslog.LOG_LOCAL4
	if config.Facility != "" {
		val, ok := stringFacilityMap[strings.ToUpper(config.Facility)]
		if !ok {
			val, ok = stringFacilityMap["LOG_"+strings.ToUpper(config.Facility)]
		}
		if ok {
			logFacility = val
		} else {
			logger.Warnf("unable to parse log facility '%s' from config, defaulting to %s", config.Facility, facilityStringMap[logFacility])
		}
	}

	logTag := "sandstorm-default"
	if config.Tag != "" {
		logTag = config.Tag
	}

	hostStr := logHost + ":514"
	// Add Central logging
	hook, err := logrus_syslog.NewSyslogHook("udp", hostStr, logFacility, logTag)

	if err != nil {
		logger.Warnf("unable to connect to syslog host '%s' with facility %s: %s", hostStr, facilityStringMap[logFacility], err)
	} else {
		logger.Debugf("set up syslog to host '%s' with facility %s tag %s", hostStr, facilityStringMap[logFacility], logTag)
		logger.Hooks.Add(hook)
	}

	return logger
}
