package main

import (
	"context"
	"encoding/json"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"

	"git.tornberg.me/mats/go-redis-inventory/pkg/inventory"
	"github.com/matst80/slask-finder/pkg/index"
	"github.com/matst80/slask-finder/pkg/messaging"
	"github.com/redis/go-redis/v9"
	"github.com/redis/go-redis/v9/maintnotifications"

	amqp "github.com/rabbitmq/amqp091-go"
)

type Server struct {
	service *inventory.RedisInventoryService
}

func (srv *Server) livezHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("OK"))
}

func (srv *Server) readyzHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("OK"))
}

func (srv *Server) getInventoryHandler(w http.ResponseWriter, r *http.Request) {
	// Parse path: /inventory/{sku}/{location}
	path := r.URL.Path
	parts := strings.Split(strings.Trim(path, "/"), "/")
	if len(parts) != 3 || parts[0] != "inventory" {
		http.Error(w, "Invalid path", http.StatusBadRequest)
		return
	}
	sku := inventory.SKU(parts[1])
	locationID := inventory.LocationID(parts[2])

	quantity, err := srv.service.GetInventory(r.Context(), sku, locationID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	response := map[string]int64{"quantity": quantity}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

var country = "se"
var redisAddress = "10.10.3.18:6379"
var redisPassword = "slaskredis"

func init() {
	// Override redis config from environment variables if set
	if addr, ok := os.LookupEnv("REDIS_ADDRESS"); ok {
		redisAddress = addr
	}
	if password, ok := os.LookupEnv("REDIS_PASSWORD"); ok {
		redisPassword = password
	}
	if ctry, ok := os.LookupEnv("COUNTRY"); ok {
		country = ctry
	}
}

func main() {
	var ctx = context.Background()
	rdb := redis.NewClient(&redis.Options{
		Addr:     redisAddress,
		Password: redisPassword, // no password set
		DB:       0,             // use default DB
		MaintNotificationsConfig: &maintnotifications.Config{
			Mode: maintnotifications.ModeDisabled,
		},
	})
	s, err := inventory.NewRedisInventoryService(rdb)
	if err != nil {
		log.Fatalf("Unable to connect to inventory redis: %v", err)
		return
	}

	server := &Server{service: s}

	// Set up HTTP routes
	http.HandleFunc("/livez", server.livezHandler)
	http.HandleFunc("/readyz", server.readyzHandler)
	http.HandleFunc("/inventory/", server.getInventoryHandler)

	stockhandler := &StockHandler{
		MainStockLocationID: inventory.LocationID(country),
		rdb:                 rdb,
		ctx:                 ctx,
		svc:                 *s,
	}

	amqpUrl, ok := os.LookupEnv("RABBIT_HOST")
	if ok {
		log.Printf("Connecting to rabbitmq")
		conn, err := amqp.DialConfig(amqpUrl, amqp.Config{
			Properties: amqp.NewConnectionProperties(),
		})
		//a.conn = conn
		if err != nil {
			log.Fatalf("Failed to connect to RabbitMQ: %v", err)
		}
		ch, err := conn.Channel()
		if err != nil {
			log.Fatalf("Failed to open a channel: %v", err)
		}
		// items listener
		err = messaging.ListenToTopic(ch, country, "item_added", func(d amqp.Delivery) error {
			var items []*index.DataItem
			err := json.Unmarshal(d.Body, &items)
			if err == nil {
				log.Printf("Got upserts %d, message count %d", len(items), d.MessageCount)
				wg := &sync.WaitGroup{}
				for _, item := range items {
					stockhandler.HandleItem(item, wg)
				}
				wg.Wait()
				log.Print("Batch done...")
			} else {
				log.Printf("Failed to unmarshal upsert message %v", err)
			}
			return err
		})
		if err != nil {
			log.Fatalf("Failed to listen to item_added topic: %v", err)
		}
	}

	// Start HTTP server
	log.Println("Starting HTTP server on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}
