package models

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strings"

	"git.paulbsd.com/paulbsd/ipbl/src/config"
	"github.com/labstack/echo/v4"
)

//const ipv4_regex = `^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})/`
const ipv4_cidr_regex = `^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|)){4}\/([1-3])?([0-9])?$)`

func GetTrustlists(cfg config.Config) (res []string, err error) {
	var w []CfgTrustlist
	err = cfg.Db.Find(&w)

	if len(w) > 0 {
		for _, a := range w {
			res = append(res, a.IP)
		}
	}
	return
}

func (wl CfgTrustlist) InsertOrUpdate(cfg config.Config) (err error) {
	var w = Cfg{Key: "trustlist"}
	exists, _ := cfg.Db.Get(&w)

	if exists {
		existing, _ := GetTrustlists(cfg)
		for _, j := range existing {
			if j == wl.IP {
				return fmt.Errorf("ip %s already in config", j)
			}
		}
		existing = append(existing, wl.IP)
		w.Value = strings.Join(existing, ",")
		cfg.Db.ID(w.ID).Update(&w)
	}
	return fmt.Errorf("no trustlist updated")
}

func (wl CfgTrustlist) Delete(cfg config.Config, ip string) (affected int64, err error) {
	var w = CfgTrustlist{IP: ip}
	exists, _ := cfg.Db.Get(&w)

	if exists {
		affected, err = cfg.Db.ID(w.ID).Update(&w)
		return
	}
	return
}

func (wl CfgTrustlist) Verify() bool {
	reg := regexp.MustCompile(ipv4_cidr_regex)
	return reg.MatchString(wl.IP)
}

func GetSets(cfg config.Config) (res []CfgSet, err error) {
	var w = []CfgSet{}

	if err := cfg.Db.Where("enabled is true").Find(&w); err == nil {
		return w, err
	}
	return
}

func GetGlobalConfig(cfg config.Config) (res []Cfg, err error) {
	var w = []Cfg{}

	if err := cfg.Db.Find(&w); err == nil {
		return w, err
	}
	return
}

func InsertOrUpdateSets(cfg config.Config, folders []CfgSet) (res string, err error) {
	var w = Cfg{Key: "folders"}

	if exists, _ := cfg.Db.Get(&w); exists {
		resbytes, err := json.Marshal(folders)
		if err != nil {
			return "", err
		}
		w.Value = string(resbytes)
		_, err = cfg.Db.ID(w.ID).Update(&w)
		if err != nil {
			return "", err
		}
	}
	return
}

func GetZMQ(cfg config.Config) (res []CfgZMQ, err error) {
	var w = []CfgZMQ{}

	if err = cfg.Db.Find(&w); err == nil {
		return w, err
	}
	return
}

func DiscoverURLS(cfg config.Config, routes []*echo.Route) (Discovery, error) {
	var disc Discovery
	var urls = make(map[string]Url)
	for _, j := range routes {
		if strings.Contains(j.Path, ":") || j.Path == "/" || j.Path == "/discovery" {
			continue
		}
		names := strings.Split(j.Path, "/")
		name := names[len(names)-1]
		urls[name] = Url{Key: name, Path: j.Path}
	}
	disc = Discovery{Version: "1.0", URLs: urls}
	return disc, nil
}

type CfgTrustlist struct {
	ID int    `xorm:"pk autoincr" json:"-"`
	IP string `xorm:"text notnull" json:"ip"`
}

type CfgZMQ struct {
	ID           int    `xorm:"pk autoincr" json:"-"`
	Type         string `xorm:"text notnull" json:"type"`
	Hostname     string `xorm:"text notnull" json:"hostname"`
	Port         int    `json:"port"`
	Subscription string `json:"subscription"`
}

type CfgSet struct {
	ID        int    `xorm:"pk autoincr" json:"-"`
	Path      string `xorm:"text notnull default" json:"path"`
	Src       string `xorm:"text notnull" json:"src"`
	Filename  string `xorm:"text notnull" json:"filename"`
	Regex     string `xorm:"text notnull" json:"regex"`
	Blocktime int64  `xorm:"notnull default 60" json:"blocktime"`
	Enabled   bool   `xorm:"notnull default true" json:"-"`
}

type Cfg struct {
	ID    int    `xorm:"pk autoincr" json:"-"`
	Key   string `xorm:"text notnull unique" json:"key"`
	Value string `xorm:"text default" json:"value"`
}

type Discovery struct {
	Version string         `json:"version"`
	URLs    map[string]Url `json:"urls"`
}

type Url struct {
	Key  string `json:"key"`
	Path string `json:"path"`
}
