package qrz

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"

	"git.paulbsd.com/paulbsd/qrz/src/config"
	"github.com/antchfx/htmlquery"
	"github.com/jmoiron/sqlx"
	"golang.org/x/text/encoding/charmap"
)

// GetBody fetch html page
func GetBody(config config.Config) (string, error) {
	var client http.Client

	resp, err := client.Get(config.FrsConfig.URL)
	if err != nil {
		return "", err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	dec := charmap.ISO8859_1.NewDecoder()
	output, _ := dec.Bytes(body)
	bodyString := string(output)

	return bodyString, nil
}

// GetFrsEntries get FRS entries from html body
func GetFrsEntries(config config.Config, body string) (frsentries map[string]FrsEntry, err error) {
	frsentries = make(map[string]FrsEntry)
	re := regexp.MustCompile(config.FrsConfig.Regex)

	htmlpage, err := htmlquery.Parse(strings.NewReader(body))
	if err != nil {
		return
	}

	for _, n := range htmlquery.Find(htmlpage, config.FrsConfig.XPath) {
		td := htmlquery.Find(n, "//td")
		if re.MatchString(htmlquery.InnerText(td[0])) {
			frs := FrsEntry{
				QRZ:     strings.Replace(htmlquery.InnerText(td[0]), "'", "\\'", -1),
				Name:    strings.Replace(htmlquery.InnerText(td[1]), "'", "\\'", -1),
				City:    strings.Replace(htmlquery.InnerText(td[2]), "'", "\\'", -1),
				Dept:    strings.Replace(htmlquery.InnerText(td[3]), "'", "\\'", -1),
				Country: strings.Replace(htmlquery.InnerText(td[4]), "'", "\\'", -1)}
			frsentries[frs.QRZ] = frs
		}
	}

	return
}

// GetCurrentEntries fetch existing entries from database
func GetCurrentEntries(config config.Config, db sqlx.DB) (existingQRZ []string, err error) {
	q := fmt.Sprintf(config.Statements.DbGetQrz, config.DbTable)
	rows, err := db.Query(q)

	for rows.Next() {
		var i string
		rows.Scan(&i)
		existingQRZ = append(existingQRZ, i)
	}

	return
}

// DiscardExistingEntries remove existing entries from original map[string]FrsEntry
func DiscardExistingEntries(config config.Config, frsPeople *map[string]FrsEntry, existingQRZ []string) (err error) {
	for _, entry := range existingQRZ {
		delete(*frsPeople, entry)
	}

	return
}

// InsertFrsEntryToDB inserts frs entries to database
func InsertFrsEntryToDB(config config.Config, db sqlx.DB, frsPeople map[string]FrsEntry) (err error) {
	tx := db.MustBegin()
	var qrzNum int

	fmt.Println(fmt.Sprintf("Starting inserts of %d entries", len(frsPeople)))

	for _, j := range frsPeople {
		query := fmt.Sprintf(config.Statements.DbInsert, config.DbTable, j.QRZ, j.Name, j.City, j.Dept, j.Country)
		tx.MustExec(query)
		qrzNum++
	}

	err = tx.Commit()
	if err != nil {
		return err
	}
	fmt.Println(fmt.Sprintf("Committed %d qrz entries", qrzNum))

	return nil
}

// FrsEntry describe FRS people
type FrsEntry struct {
	QRZ     string `db:"qrz"`
	Name    string `db:"name"`
	City    string `db:"city"`
	Dept    string `db:"dept"`
	Country string `db:"country"`
}
