package towmanparklocation

import (
	"sync"
	"time"

	"github.com/fiskerinc/cloud-services/pkg/cachev2"
	"github.com/fiskerinc/cloud-services/pkg/db"
	"github.com/fiskerinc/cloud-services/pkg/logger"
	"github.com/fiskerinc/cloud-services/pkg/redisv2"
)

func (plt *ParkLocationTracker) VCUGearSig(vin string, newState int) {
	// Fast exit if the car is not being parked
	if newState != 1 {
		return
	}
	_, ok := plt.WatchList[vin]
	if !ok {
		return
	}

	// WRITE park location to DB
	// DOn't want to slow down the signal processing, so do this async
	go plt.recordParkLocation(vin)
}

// Probably would be better with a channel and a worker, but this is fine for now
func (plt *ParkLocationTracker) recordParkLocation(vin string) {
	// Fetch the location from redis -- how did copilot know this?
	location, err := cachev2.GetVehicleLocation(vin, plt.RedisClient)
	if err != nil {
		logger.Err(err).Str("VIN", vin).Msg("failed to get vehicle location for park location")
		return
	}

	// Write to DB
	_, err = plt.DBClient.GetConn().Exec("INSERT INTO towman.parked_locations (vin, latitude, longitude) VALUES (?, ?, ?)", vin, location.Latitude, location.Longitude)
	if err != nil {
		logger.Err(err).Str("VIN", vin).Msg("failed to record park location to DB")
		return
	}
}

func (plt *ParkLocationTracker) UpdateVehicleList() {
	dbVINS := []string{}
	_, err := plt.DBClient.GetConn().Query(&dbVINS, "SELECT vin FROM towman.vehicles")
	if err != nil {
		logger.Err(err).Msg("failed to update parked vehicle list")
		return
	}
	// Make anew watchmap
	newWatchList := make(map[string]struct{})
	for _, vin := range dbVINS {
		newWatchList[vin] = struct{}{}
	}

	// Only need to lock before we assign the new map
	plt.WatchListSync.Lock()
	defer plt.WatchListSync.Unlock()
	// assign watchmap
	plt.WatchList = newWatchList
}

func (plt *ParkLocationTracker) IsVehicleWatched(vin string) (watched bool) {
	plt.WatchListSync.RLock()
	_, ok := plt.WatchList[vin]
	plt.WatchListSync.RUnlock()
	return ok
}

func InitParkLocationTracker(dbClient *db.DBClient, redisClient *redisv2.Connection) (plt *ParkLocationTracker) {
	plt = &ParkLocationTracker{
		WatchList: make(map[string]struct{}),
	}
	plt.DBClient = dbClient
	plt.RedisClient = redisClient
	go plt.SeedDaily()
	return
}

// This list won't update that often
func (plt *ParkLocationTracker) SeedDaily() {
	plt.UpdateVehicleList()
	time.AfterFunc(time.Hour*24, plt.SeedDaily)
}

type ParkLocationTracker struct {
	WatchList     map[string]struct{} // VINs being tracked for parking location
	DBClient      *db.DBClient
	RedisClient   *redisv2.Connection
	WatchListSync sync.RWMutex
}
