package config

import (
	"flag"
	"fmt"
	"os"
	"time"

	loadconfig "backend-agenter/pkg/loadconfig"

	"github.com/spf13/viper"
	"go.uber.org/zap"
)

var EnvPath = flag.String("envfile", "", "string, sets path to .env file")

type Config struct {
	App       *App       `mapstructure:"app"`
	Postgres  *Postgres  `mapstructure:"postgres"`
	Agent     *Agent     `mapstructure:"agent"`
	Transport *Transport `mapstructure:"transport"`
}

type App struct {
	Mode string `mapstructure:"mode"`
}

type Postgres struct {
	Protocol       string        `mapstructure:"protocol"`
	URL            string        `mapstructure:"url"`
	Port           int           `mapstructure:"port"`
	Username       string        `mapstructure:"username"`
	Password       string        `mapstructure:"password"`
	Database       string        `mapstructure:"database"`
	AvObjectsTable string        `mapstructure:"av_objects_table"`
	UrlsTable      string        `mapstructure:"urls_table"`
	Timeout        time.Duration `mapstructure:"timeout"`
}

type Agent struct {
	Timeout      time.Duration `mapstructure:"timeout"`
	ModuleName   string        `mapstructure:"module_name"`
	FullScan     bool          `mapstructure:"full_scan"`
	IsQuarantine bool          `mapstructure:"is_quarantine"`
}

type Transport struct {
	URL              string        `mapstructure:"host"`
	Port             uint16        `mapstructure:"port"`
	Type             string        `mapstructure:"type"`
	Name             string        `mapstructure:"name"`
	Version          int32         `mapstructure:"version"`
	Class            int32         `mapstructure:"class"`
	ConcurrencyLimit uint32        `mapstructure:"concurrency_limit"`
	Timeout          time.Duration `mapstructure:"timeout"`
}

type File struct {
	Path   string `mapstructure:"path"`
	Name   string `mapstructure:"name"`
	Format string `mapstructure:"format"`
}

func (c *Postgres) GetAddr() string {
	return fmt.Sprintf("%s://%s:%s@%s:%d/%s", c.Protocol, c.Username, c.Password, c.URL, c.Port, c.Database)
}

func NewFile() *File {
	return &File{
		Path:   os.Getenv("CONFIG_FILE_PATH"),
		Name:   os.Getenv("CONFIG_FILE_NAME"),
		Format: os.Getenv("CONFIG_FILE_FORMAT"),
	}
}

func New() (*Config, error) {
	envs := []string{"CONFIG_FILE_PATH", "CONFIG_FILE_NAME", "CONFIG_FILE_FORMAT"}

	err := loadconfig.CheckEnvs(envs)
	if err != nil {
		return nil, err
	}

	configFile := NewFile()
	err = loadconfig.LoadConfig(configFile.Path, configFile.Name, configFile.Format)
	if err != nil {
		return nil, err
	}

	c := &Config{}
	err = viper.Unmarshal(c)
	if err != nil {
		zap.S().Errorf("Error while unmarshal config: %v", err)
		return nil, err
	}

	return c, nil
}
