package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/nsqio/go-nsq"
)

var Error *log.Logger
var Warning *log.Logger

func init() {
	log.SetFlags(log.Lmicroseconds | log.Lshortfile)
	logFile, err := os.Create("main.log")
	if err != nil {
		log.Printf("Error creating log file: %v", err)
		os.Exit(1)
	}
	logger := io.MultiWriter(os.Stdout, logFile)
	log.SetOutput(logger)

	Error = log.New(io.MultiWriter(logFile, os.Stderr, os.Stdout),
		fmt.Sprintf("%sERROR:%s ", "\033[0;101m", "\033[0m"),
		log.Lmicroseconds|log.Lshortfile)
	Warning = log.New(io.MultiWriter(logFile, os.Stdout),
		fmt.Sprintf("%sWarning:%s ", "\033[0;93m", "\033[0m"),
		log.Lmicroseconds|log.Lshortfile)
}

const DOWNLOAD_WORKERS = 50

var whitelistedAchievements = map[string]bool{
	"15":    true,
	"958":   true,
	"1276":  true,
	"2088":  true,
	"2151":  true,
	"5466":  true,
	"5759":  true,
	"6470":  true,
	"6763":  true,
	"7392":  true,
	"7393":  true,
	"7394":  true,
	"7958":  true,
	"8939":  true,
	"8992":  true,
	"9048":  true,
	"94103": true,
	"10059": true,
	"10079": true,
	"10278": true,
	"10657": true,
	"10672": true,
	"10684": true,
	"10688": true,
	"10689": true,
	"10692": true,
	"10693": true,
	"10698": true,
	"10790": true,
	"10875": true,
	"11124": true,
	"11126": true,
	"11127": true,
	"11128": true,
	"11157": true,
	"11164": true,
	"11188": true,
	"11189": true,
	"11190": true,
	"11446": true,
	"11473": true,
	"11610": true,
	"11674": true,
	"11992": true,
	"11993": true,
	"11994": true,
	"11995": true,
	"11996": true,
	"11997": true,
	"11998": true,
	"11999": true,
	"12000": true,
	"12001": true,
	"12026": true,
	"12074": true,
	"12445": true,
	"12447": true,
	"12448": true,
}

type MsgHandler struct{}

func (*MsgHandler) HandleMessage(message *nsq.Message) error {
	log.Printf("Received message '%s' with %d attempts", message.Body, message.Attempts)
	data := NSQMessage{}
	err := json.Unmarshal(message.Body, &data)
	if err != nil {
		Error.Printf("Error unmarshalling message: %v", err)
		return err
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		ticker := time.NewTicker(5 * time.Second)
		defer ticker.Stop()

		for {
			select {
			case <-ticker.C:
				message.Touch()
			case <-ctx.Done():
				return
			}
		}
	}()

	_, ok := whitelistedAchievements[data.ID]
	if !ok {
		Warning.Printf("Received message for non-whitelisted achievement %s", data.ID)
		return nil
	}

	_, err = db.writeConn.Exec("INSERT OR IGNORE INTO achievements (name, id, date, completed) VALUES (?, ?, ?, ?)",
		data.Name, data.ID, data.Date, data.Completed)
	if err != nil {
		Error.Printf("Error inserting into database: %v", err)
		return err
	}

	message.Finish()
	return nil
}

var db DB

func main() {
	config := nsq.NewConfig()
	config.MaxAttempts = 5
	config.MaxInFlight = DOWNLOAD_WORKERS
	config.MsgTimeout = 10 * time.Second

	db = DB{
		path: "../data/db.db",
	}
	err := db.Open()
	if err != nil {
		Error.Printf("Error opening database: %v", err)
		return
	}
	defer db.Close()

	consumer, err := nsq.NewConsumer("wowspy", "achievement", config)
	if err != nil {
		Error.Printf("Error creating consumer: %v", err)
		return
	}
	for i := 0; i < DOWNLOAD_WORKERS; i++ {
		consumer.AddHandler(&MsgHandler{})
	}

	url := "192.168.1.123:41505"
	err = consumer.ConnectToNSQD(url)
	if err != nil {
		Error.Printf("Error connecting to nsqlookupd: %v", err)
		return
	}

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	<-sigChan
	log.Println("Received signal to terminate. Initiating graceful shutdown...")

	consumer.Stop()
	<-consumer.StopChan

	log.Println("Graceful shutdown completed.")
}
