package main

import (
	"fmt"

	"strings"

	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/widget"
	"github.com/gocolly/colly/v2"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/layout"

	"strconv"

	"fyne.io/fyne/v2/driver/mobile"
)

type numericalEntry struct {
	widget.Entry
}

func newNumericalEntry() *numericalEntry {
	entry := &numericalEntry{}
	entry.ExtendBaseWidget(entry)
	return entry
}

func (e *numericalEntry) TypedRune(r rune) {
	if (r >= '0' && r <= '9') || r == '.' || r == ',' {
		e.Entry.TypedRune(r)
	}
}

func (e *numericalEntry) TypedShortcut(shortcut fyne.Shortcut) {
	paste, ok := shortcut.(*fyne.ShortcutPaste)
	if !ok {
		e.Entry.TypedShortcut(shortcut)
		return
	}

	content := paste.Clipboard.Content()
	if _, err := strconv.ParseFloat(content, 64); err == nil {
		e.Entry.TypedShortcut(shortcut)
	}
}

func (e *numericalEntry) Keyboard() mobile.KeyboardType {
	return mobile.NumberKeyboard
}

type vehicle struct {
	producer                   string
	model                      string
	production_year            string
	traction_type              string
	vehicle_registration_plate string
	vehicle_number             string
	operator                   string
	garage                     string
	ticket_machine             string
	equipment                  string
}

func vehicleToString(inputVehicle *vehicle) string {
	registrationPlate := ""
	if len(inputVehicle.vehicle_registration_plate) > 0 {
		registrationPlate = fmt.Sprintf(`,o rejestracji %s`, inputVehicle.vehicle_registration_plate)
	}
	output_string := fmt.Sprintf(
		"%s o numerze %s,"+"%s %s,"+"z roku %s,"+"w posiadaniu %s,"+"z zajezdni %s%s",
		inputVehicle.traction_type,
		inputVehicle.vehicle_number,
		inputVehicle.producer,
		inputVehicle.model,
		inputVehicle.production_year,
		inputVehicle.operator,
		inputVehicle.garage,
		registrationPlate)
	return strings.Replace(output_string, ",", ",\n", -1)
}

func getVehiclesByNum(vehicleNum string) string {
	searchURL := fmt.Sprintf("https://www.ztm.waw.pl/baza-danych-pojazdow/?ztm_traction=&ztm_make=&ztm_model=&ztm_year=&ztm_registration=&ztm_vehicle_number=%s&ztm_carrier=&ztm_depot=", vehicleNum)
	var vehicleURLs []string

	c2 := colly.NewCollector(
		// Visit only domains:
		colly.AllowedDomains("www.ztm.waw.pl"),
	)
	c2.OnHTML(".grid-row-active", func(e *colly.HTMLElement) {
		text := e.Attr("href")
		vehicleURLs = append(vehicleURLs, text)
	})
	c2.Visit(searchURL)
	output_string := ""
	for _, vehicleURL := range vehicleURLs {
		var retrievedData [10]string
		// Instantiate default collector
		c := colly.NewCollector(
			// Visit only domains:
			colly.AllowedDomains("www.ztm.waw.pl"),
		)
		dataIndex := 0
		c.OnHTML(".vehicle-details-entry-value", func(e *colly.HTMLElement) {
			text := e.Text
			retrievedData[dataIndex] = text
			dataIndex++
		})
		c.Visit(vehicleURL)
		retrievedVehicle := vehicle{
			producer:                   retrievedData[0],
			model:                      retrievedData[1],
			production_year:            retrievedData[2],
			traction_type:              retrievedData[3],
			vehicle_registration_plate: retrievedData[4],
			vehicle_number:             retrievedData[5],
			operator:                   retrievedData[6],
			garage:                     retrievedData[7],
			ticket_machine:             retrievedData[8],
			equipment:                  retrievedData[9],
		}
		output_string += vehicleToString(&retrievedVehicle)
		output_string += "\n"
		output_string += "\n"
	}
	return output_string
}

func main() {
	a := app.New()
	w := a.NewWindow("ZTM vehicles")

	entryLabel := widget.NewLabel("Podaj numer taborowy pojazdu:")
	entry := newNumericalEntry()
	output := widget.NewLabel("")
	output.Wrapping = fyne.TextWrapWord

	//outputContainer := container.NewVScroll(output)
	//I create button earlier in order to reference it later inside function of it so I can easily disable it for the time data is fetching. There is probably better way to do it but I could't find it so
	executeButton := widget.NewButton("Sprawdź numer", func() {
		output.Refresh()
	})
	executeButton = widget.NewButton("Sprawdź numer", func() {
		executeButton.Disable()
		executeButton.SetText("Wczytywanie")
		if len(strings.TrimSpace(entry.Text)) != 0 {
			output_data := getVehiclesByNum(entry.Text)
			if output_data != "" {
				output.Text = output_data
			} else {
				output.Text = "Nie znaleziono pojazdu o podanym numerze taborowym w bazie pojazdów WTP"
			}
		} else {
			output.Text = "Nie wprowadzono prawidłowego numeru"
		}

		output.Refresh()
		executeButton.Enable()
		executeButton.SetText("Sprawdź numer")
	})
	executeButton.Importance = widget.HighImportance

	clearButton := widget.NewButton("Wyczyść", func() {
		entry.Text = ""
		output.Text = ""
		output.Refresh()
		entry.Refresh()
	})
	buttons := container.New(layout.NewGridLayout(2), clearButton, executeButton)
	inputs := container.New(layout.NewGridLayout(1), entryLabel, entry, buttons)

	w.SetContent(container.NewVBox(
		inputs,
		output,
	))

	w.ShowAndRun()
}