package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/bogosj/tesla"
	"github.com/therecipe/qt/widgets"
)

var (
	// Info/Statuses
	batteryLevel      *widgets.QLineEdit
	batteryRange      *widgets.QLineEdit
	chargingState     *widgets.QLineEdit
	minutesToFull     *widgets.QLineEdit
	fastChargerInd    *widgets.QLineEdit
	batteryHeaterInd  *widgets.QLineEdit
	chargeDoorOpenInd *widgets.QLineEdit
	insideTemp        *widgets.QLineEdit
	outsideTemp       *widgets.QLineEdit

	// Controls
	tempSetting     *widgets.QLineEdit
	climateOn       *widgets.QCheckBox
	lockedDoors     *widgets.QCheckBox
	sentryMode      *widgets.QCheckBox
	startStopCharge *widgets.QCheckBox

	honk        *widgets.QPushButton
	flashLights *widgets.QPushButton
	trunk       *widgets.QPushButton
	frunk       *widgets.QPushButton

	vehicle      *tesla.Vehicle
	vehicleState *tesla.VehicleState
	chargeStats  *tesla.ChargeState
	climateState *tesla.ClimateState
	guiSettings  *tesla.GuiSettings

	window  *widgets.QMainWindow
	mainApp *widgets.QApplication
	popup   = false
)

func main() {
	mainApp = widgets.NewQApplication(len(os.Args), os.Args)

	vboxLayout := widgets.NewQVBoxLayout()
	statusLayout := widgets.NewQFormLayout(nil)

	batteryLevel = widgets.NewQLineEdit(nil)
	batteryLevel.SetReadOnly(true)
	batteryLevel.SetFixedWidth(30)
	batteryRange = widgets.NewQLineEdit(nil)
	batteryRange.SetReadOnly(true)
	chargingState = widgets.NewQLineEdit(nil)
	chargingState.SetReadOnly(true)
	minutesToFull = widgets.NewQLineEdit(nil)
	minutesToFull.SetReadOnly(true)
	fastChargerInd = widgets.NewQLineEdit(nil)
	fastChargerInd.SetReadOnly(true)
	batteryHeaterInd = widgets.NewQLineEdit(nil)

	batteryHeaterInd.SetReadOnly(true)
	chargeDoorOpenInd = widgets.NewQLineEdit(nil)
	chargeDoorOpenInd.SetReadOnly(true)
	insideTemp = widgets.NewQLineEdit(nil)
	insideTemp.SetReadOnly(true)
	insideTemp.SetFixedWidth(25)
	outsideTemp = widgets.NewQLineEdit(nil)
	outsideTemp.SetReadOnly(true)
	outsideTemp.SetFixedWidth(25)
	tempSetting = widgets.NewQLineEdit(nil)
	tempSetting.SetFixedWidth(25)

	climateOn = widgets.NewQCheckBox(nil)
	lockedDoors = widgets.NewQCheckBox(nil)
	sentryMode = widgets.NewQCheckBox(nil)

	startStopCharge = widgets.NewQCheckBox(nil)

	honk = widgets.NewQPushButton(nil)
	flashLights = widgets.NewQPushButton(nil)
	trunk = widgets.NewQPushButton(nil)
	frunk = widgets.NewQPushButton(nil)

	currentChargeLabel := widgets.NewQLabel(nil, 0)
	currentChargeLabel.SetText("Current Charge: ")
	currentRangeLabel := widgets.NewQLabel(nil, 0)
	currentRangeLabel.SetText("Current Range: ")
	chargeHbox := widgets.NewQHBoxLayout()
	chargeHbox.AddWidget(batteryLevel, 0, 0)
	chargeHbox.AddItem(widgets.NewQSpacerItem(5, 2, widgets.QSizePolicy__Expanding, widgets.QSizePolicy__Expanding))
	chargeHbox.AddWidget(currentRangeLabel, 0, 0)
	chargeHbox.AddWidget(batteryRange, 0, 0)
	statusLayout.AddRow2(currentChargeLabel, chargeHbox)

	setValues()
	statusLayout.AddRow3("Charging State: ", chargingState)
	if chargeStats.ChargingState != "Disconnected" {
		statusLayout.AddRow3("Minutes to Full: ", minutesToFull)
		if chargeStats.FastChargerPresent {
			statusLayout.AddRow3("Fast Charger: ", fastChargerInd)
		}
		if chargeStats.BatteryHeaterOn {
			statusLayout.AddRow3("Battey Heater: ", batteryHeaterInd)
		}
	}
	statusLayout.AddRow3("Charge Port: ", chargeDoorOpenInd)

	insideTempLabel := widgets.NewQLabel(nil, 0)
	outsideTempLabel := widgets.NewQLabel(nil, 0)

	insideTempLabel.SetText("Inside Temp: ")
	outsideTempLabel.SetText("Outside Temp: ")
	tempHbox := widgets.NewQHBoxLayout()
	tempHbox.AddWidget(insideTemp, 0, 0)
	tempHbox.AddItem(widgets.NewQSpacerItem(10, 10, widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed))
	tempHbox.AddWidget(outsideTempLabel, 0, 0)
	tempHbox.AddWidget(outsideTemp, 0, 0)
	statusLayout.AddRow2(insideTempLabel, tempHbox)

	climateEnabledLabel := widgets.NewQLabel(nil, 0)
	climateEnabledLabel.SetText("Climate On: ")
	climateSettingLabel := widgets.NewQLabel(nil, 0)
	climateSettingLabel.SetText("Climate Setting: ")

	climateHbox := widgets.NewQHBoxLayout()
	climateHbox.AddWidget(climateOn, 0, 0)
	climateHbox.AddItem(widgets.NewQSpacerItem(10, 10, widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed))
	climateHbox.AddWidget(climateSettingLabel, 0, 0)
	climateHbox.AddWidget(tempSetting, 0, 0)
	statusLayout.AddRow2(climateEnabledLabel, climateHbox)

	doorLockLabel := widgets.NewQLabel(nil, 0)
	sentryModeLabel := widgets.NewQLabel(nil, 0)
	chargingStateLabel := widgets.NewQLabel(nil, 0)

	doorLockLabel.SetText("Lock Doors: ")
	sentryModeLabel.SetText("Sentry Mode: ")
	chargingStateLabel.SetText("Charging: ")
	securityHbox := widgets.NewQHBoxLayout()
	securityHbox.AddWidget(lockedDoors, 0, 0)
	securityHbox.AddItem(widgets.NewQSpacerItem(10, 10, widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed))
	securityHbox.AddWidget(sentryModeLabel, 0, 0)
	securityHbox.AddWidget(sentryMode, 0, 0)
	if chargeStats.ChargingState != "Disconnected" {
		securityHbox.AddItem(widgets.NewQSpacerItem(10, 10, widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed))
		securityHbox.AddWidget(chargingStateLabel, 0, 0)
		securityHbox.AddWidget(startStopCharge, 0, 0)
	}

	lockedDoors.ConnectStateChanged(lockDoors)
	sentryMode.ConnectStateChanged(sentryModeEnable)
	startStopCharge.ConnectStateChanged(enableCharging)
	climateOn.ConnectStateChanged(enableClimate)
	statusLayout.AddRow2(doorLockLabel, securityHbox)

	honk = widgets.NewQPushButton(nil)
	flashLights = widgets.NewQPushButton(nil)
	trunk = widgets.NewQPushButton(nil)
	frunk = widgets.NewQPushButton(nil)

	honk.ConnectClicked(honkHorn)
	honk.SetText("Honk")
	flashLights.ConnectClicked(flash)
	flashLights.SetText("Flash")
	trunk.ConnectClicked(openTrunk)
	trunk.SetText("Trunk")
	frunk.ConnectClicked(openFrunk)
	frunk.SetText("Frunk")

	actionHbox := widgets.NewQHBoxLayout()
	actionHbox.AddWidget(honk, 0, 0)
	actionHbox.AddItem(widgets.NewQSpacerItem(2, 2, widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed))

	actionHbox.AddWidget(flashLights, 0, 0)
	actionHbox.AddItem(widgets.NewQSpacerItem(2, 2, widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed))

	actionHbox.AddWidget(trunk, 0, 0)
	actionHbox.AddItem(widgets.NewQSpacerItem(2, 2, widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed))

	actionHbox.AddWidget(frunk, 0, 0)
	actionHbox.AddItem(widgets.NewQSpacerItem(2, 2, widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed))

	statusLayout.AddRow6(actionHbox)

	vboxLayout.AddItem(statusLayout)

	window = widgets.NewQMainWindow(nil, 0)
	window.SetWindowTitle(fmt.Sprintf("%+v: %+v", vehicle.DisplayName, vehicle.Vin))
	centralWidget := widgets.NewQWidget(window, 0)
	centralWidget.SetLayout(vboxLayout)
	window.SetCentralWidget(centralWidget)
	if !popup {
		window.Show()
	}
	widgets.QApplication_Exec()
}

func setValues() {
	vehicle = getVehicle("")
	var err error
	if vehicle == nil {
		showDialogue("Unable to get vehicle")
		return
	}
	vehicleState, err = vehicle.VehicleState()
	if err != nil {
		showDialogue("Unable to get Vehicle State")
	}
	chargeStats, err = vehicle.ChargeState()
	if err != nil {

		showDialogue("Unable to get Vehicle Charge State")
	}
	climateState, err = vehicle.ClimateState()
	if err != nil {
		showDialogue("Unable to get Vehicle Climate")
	}
	guiSettings, err = vehicle.GuiSettings()
	if err != nil {

		showDialogue("Unable to get Gui Settings")
	}
	tempSettingVal := climateState.DriverTempSetting
	insideTempVal := climateState.InsideTemp
	outsideTempVal := climateState.OutsideTemp
	if guiSettings.GuiTemperatureUnits == "F" {
		tempSettingVal = (climateState.DriverTempSetting * 1.8) + 32
		insideTempVal = (climateState.InsideTemp * 1.8) + 32
		outsideTempVal = (climateState.OutsideTemp * 1.8) + 32
	}
	batteryLevel.SetText(fmt.Sprintf("%+v", chargeStats.BatteryLevel))
	batteryRange.SetText(fmt.Sprintf("%.2f%+v", chargeStats.BatteryRange,
		strings.Replace(guiSettings.GuiDistanceUnits, "/hr", "", -1)))
	batteryRange.SetFixedWidth(10 * len(batteryRange.Text()))
	chargingState.SetText(chargeStats.ChargingState)

	minutesToFull.SetText(fmt.Sprintf("%+v", chargeStats.MinutesToFullCharge))

	fastChargerInd.SetText(chargeStats.FastChargerBrand)
	if chargeStats.BatteryHeaterOn {
		batteryHeaterInd.SetText("On")
	}

	if chargeStats.ChargePortDoorOpen {
		chargeDoorOpenInd.SetText("Open")
	} else {
		chargeDoorOpenInd.SetText("Closed")
	}

	insideTemp.SetText(fmt.Sprintf("%.0f", insideTempVal))
	outsideTemp.SetText(fmt.Sprintf("%.0f", outsideTempVal))
	tempSetting.SetText(fmt.Sprintf("%.0f", tempSettingVal))

	climateOn.SetChecked(climateState.IsClimateOn)
	if vehicleState != nil {
		lockedDoors.SetChecked(vehicleState.Locked)
		sentryMode.SetChecked(vehicleState.SentryMode)
	} else {
		lockedDoors.SetCheckable(false)
		sentryMode.SetCheckable(false)
	}
	startStopCharge.SetChecked(chargeStats.ChargingState == "Charging")
	if chargeStats.ChargingState == "Disconnected" {
		startStopCharge.SetCheckable(false)
	}

}

func enableClimate(i int) {
	if i == 0 {
		vehicle.StartAirConditioning()
	} else {
		vehicle.StopAirConditioning()
	}
	go setValues()
}

func lockDoors(i int) {
	if i == 0 {
		vehicle.UnlockDoors()
	} else {
		vehicle.LockDoors()
	}
	go setValues()
}

func sentryModeEnable(i int) {
	if i == 0 {
		showDialogue("Unable to disable sentry mode.\nUnsupported.")
	} else {
		vehicle.EnableSentry()
	}
	go setValues()
}

func enableCharging(i int) {
	if i == 0 {
		vehicle.StartCharging()
	} else {
		vehicle.StopCharging()
	}
	go setValues()
}

func honkHorn(c bool) {
	err := vehicle.HonkHorn()
	if err != nil {
		showDialogue("There was an error honking the horn\n%+v", err)
		fmt.Printf("%+v\n", err)
	}
}
func flash(c bool) {
	err := vehicle.FlashLights()
	if err != nil {
		showDialogue("There was an error flashing the lights\n%+v", err)
		fmt.Printf("%+v\n", err)
	}
}
func openTrunk(c bool) {
	err := vehicle.OpenTrunk("rear")
	if err != nil {
		showDialogue("There was an error opening your trunk\n%+v", err)
		fmt.Printf("%+v\n", err)
	}
}
func openFrunk(c bool) {
	err := vehicle.OpenTrunk("front")
	if err != nil {
		showDialogue("There was an error opening your frunk\n%+v", err)
		fmt.Printf("%+v\n", err)
	}
}

func showDialogue(msg string, a ...interface{}) {
	popup = true
	dialogue := widgets.NewQDialog(nil, 0)
	dialogue.SetWindowTitle("TeslaGo Alert")
	actionHBox := widgets.NewQHBoxLayout()
	formLayout := widgets.NewQFormLayout(nil)

	contBtn := widgets.NewQPushButton(nil)
	quitBtn := widgets.NewQPushButton(nil)

	contBtn.SetText("Continue")
	quitBtn.SetText("Quit")

	contBtn.ConnectClicked(func(checked bool) {
		window.Show()
		popup = false
		dialogue.Close()

		go setValues()
	})
	quitBtn.ConnectClicked(func(checked bool) {
		mainApp.Quit()
	})

	actionHBox.AddWidget(contBtn, 0, 0)
	actionHBox.AddWidget(quitBtn, 0, 0)

	message := widgets.NewQLabel(nil, 0)
	message.SetText(fmt.Sprintf(msg, a...))
	message.SetWordWrap(true)

	formLayout.AddRow5(message)
	formLayout.AddRow6(actionHBox)
	centralWidget := widgets.NewQWidget(dialogue, 0)
	centralWidget.SetLayout(formLayout)
	dialogue.SetMinimumWidth(255)
	dialogue.SetMinimumHeight(50 + (20 * (1 + strings.Count(msg, "\n"))))

	dialogue.Show()
}