package dip

import (
	"fmt"
	"log"
	"net"

	"git.paulbsd.com/paulbsd/dip/src/geoip"
	"github.com/labstack/echo/v4"
	"github.com/likexian/whois"
	whoisparser "github.com/likexian/whois-parser"
	"github.com/oschwald/geoip2-golang"
)

const defaultLanguage = "en"

var citydb *geoip2.Reader
var asndb *geoip2.Reader

func Init() (err error) {
	citydb, asndb, err = geoip.InitGeoIP()
	if err != nil {
		log.Println(err)
	}
	return
}

// GetIPInfo returns IP address informations
func (ip *IP) GetIPInfo(c echo.Context) (err error) {
	if c.Param("ip") != "" {
		ip.IP = c.Param("ip")
	} else {
		ip.IP = c.RealIP()
	}

	err = ip.CheckIPAddress()
	if err != nil {
		ip.IP = c.RealIP()
		err = ip.CheckIPAddress()
		if err != nil {
			log.Println(err)
		}
	}

	err = ip.GetHostname()
	if err != nil {
		log.Println(err)
	}

	err = ip.GetGeoIP()
	if err != nil {
		log.Println(err)
	}

	/*err = ip.GetWhois()
	if err != nil {
		log.Println(err)
	}*/

	return
}

// CheckIPAddress check if ip is an IP address, return err if there's an error
func (ip *IP) CheckIPAddress() (err error) {
	addr := net.ParseIP(ip.IP)
	if addr == nil {
		return fmt.Errorf("Supplied string isn't an IP address \"%s\"", ip.IP)
	}
	return
}

// GetHostname assign ip.Hostname value
func (ip *IP) GetHostname() (err error) {
	revip, err := net.LookupAddr(ip.IP)
	if err != nil {
		return err
	}
	ip.Hostname = revip[0]
	return
}

// GetWhois not implemented yet
func (ip *IP) GetWhois() (err error) {
	resultraw, err := whois.Whois("example.com")
	result, err := whoisparser.Parse(resultraw)
	if err != nil {
		return
	}
	fmt.Println(result)
	return
}

func (ip *IP) GetGeoIP() (err error) {
	i := net.ParseIP(ip.IP)
	city, err := citydb.City(i)
	if err != nil {
		log.Println(err)
	}
	asn, err := asndb.ASN(i)
	if err != nil {
		log.Println(err)
	}

	ip.City = city.City.Names[defaultLanguage]
	ip.Country = city.Country.Names[defaultLanguage]
	ip.As = AS{
		Number: int(asn.AutonomousSystemNumber),
		Org:    asn.AutonomousSystemOrganization,
	}

	return
}

// IP defines ip main struct
type IP struct {
	IP       string `json:"ip"`
	Hostname string `json:"hostname"`
	City     string `json:"city"`
	Country  string `json:"country"`
	As       AS     `json:"as"`
}

type AS struct {
	Number int    `json:"number"`
	Org    string `json:"org"`
}
