package globalvariables

import (
	"alpha/adDelivery/helper"
	"alpha/adDelivery/structure"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"github.com/oschwald/geoip2-golang"

	config "alpha/configuration"

	"github.com/avct/uasurfer"
)

func SetAllGrobalVariables(r *http.Request) structure.GlobalVariables {

	globalValues := structure.GlobalVariables{}
	ip, _ := getIP(r)

	ip_records, _ := GetRecord(ip)
	fmt.Println()

	globalValues.Ip_address = ip

	if ip_records != nil {
		globalValues.Latitude = strconv.FormatFloat(float64(ip_records.Location.Latitude), 'f', 2, 64)
		globalValues.Longitude = strconv.FormatFloat(float64(ip_records.Location.Longitude), 'f', 2, 64)
		globalValues.Country_code = ip_records.Country.IsoCode
		globalValues.Country_name = ip_records.Country.Names["en"]
		//~ globalValues.Subdivision_one = ip_records.Subdivisions[0].IsoCode
		globalValues.Continent = ip_records.Continent.Code
		globalValues.City = ip_records.City.Names["en"]

		if len(ip_records.Subdivisions) == 2 {
			globalValues.Subdivision_two = ip_records.Subdivisions[1].IsoCode

		}
	}

	bnname := helper.GetUrlParam(r, "bnname")

	Device := strings.SplitN(bnname, ",", 2)

	if len(Device) == 2 {

		globalValues.DeviceName = Device[0]
		globalValues.DeviceModel = Device[1]
	}

	ua := r.UserAgent()

	globalValues.Useragent = ua
	uaDetails := uasurfer.Parse(ua)

	globalValues.Browser = strings.TrimPrefix(uaDetails.Browser.Name.String(), "Browser")

	globalValues.DeviceType = strings.TrimPrefix(uaDetails.DeviceType.String(), "Device")

	globalValues.BrowserVersion = strconv.Itoa(uaDetails.Browser.Version.Major) + "." + strconv.Itoa(uaDetails.Browser.Version.Minor) + "." + strconv.Itoa(uaDetails.Browser.Version.Patch)

	globalValues.Os = strings.TrimPrefix(uaDetails.OS.Name.String(), "OS")
	globalValues.Osv = strconv.Itoa(uaDetails.OS.Version.Major) + "." + strconv.Itoa(uaDetails.OS.Version.Minor) + "." + strconv.Itoa(uaDetails.OS.Version.Patch)

	links := config.GetConfig("protocol", "webpath") + r.Host + r.URL.String()
	us, _ := url.Parse(links)

	globalValues.Hostname = parserURL(us, "Hostname")
	globalValues.DomainName = parserURL(us, "Hostname")
	globalValues.PageURL = links
	globalValues.RefURL = r.Header.Get("Referer")
	globalValues.Source = GetUrlParam(r, "loc")
	globalValues.R = r

	return globalValues
}

func parserURL(u *url.URL, name string) string {

	switch name {
	case "Hostname":
		if u.Host != "" {
			if host, _, err := net.SplitHostPort(u.Host); err == nil {
				return host
			} else {
				return u.Host
			}
		}

	}
	return ""
}

func getIP(r *http.Request) (string, error) {
	//Get IP from the X-REAL-IP header
	ip := r.Header.Get("X-REAL-IP")
	netIP := net.ParseIP(ip)
	if netIP != nil {
		return ip, nil
	}

	//Get IP from X-FORWARDED-FOR header
	ips := r.Header.Get("X-FORWARDED-FOR")
	splitIps := strings.Split(ips, ",")
	for _, ip := range splitIps {
		netIP := net.ParseIP(ip)
		if netIP != nil {
			return ip, nil
		}
	}

	//Get IP from RemoteAddr
	ip, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		return "", err
	}
	netIP = net.ParseIP(ip)
	if netIP != nil {
		return ip, nil
	}
	return "", fmt.Errorf("No valid ip found")
}

func GetRecord(ip string) (*geoip2.City, error) {

	filepath := config.GetConfig("filepath", "geommdb")
	//~ filename := "GeoLite2-City.mmdb"
	db, err := geoip2.Open(filepath)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	defer db.Close()
	// If you are using strings that may be invalid, check that ip is not nil
	ipv4 := net.ParseIP(ip)
	record, err := db.City(ipv4)
	if err != nil {
		return nil, err
	}
	return record, err
}

func GetUrlParam(r *http.Request, val string) string {

	value := r.URL.Query()[val]
	if len(value) != 0 {
		return value[0]
	} else {
		return ""
	}
}
