package main

import (
	"flag"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"github.com/reimage-ai/broker/firebase"
	"github.com/reimage-ai/broker/httpd"
	"github.com/reimage-ai/broker/job"
	"github.com/reimage-ai/broker/nsfw"
	"github.com/reimage-ai/broker/queue"
	"github.com/reimage-ai/broker/revenuecat"
)

var shutdownFlag = false

func main() {
	selfcertPtr := flag.Bool("selfcert", false, "Use a self-signed cert instead of autocert")
	logFilePtr := flag.String("logfile", "", "GIN access log path")
	jobFilePtr := flag.String("jobfile", "", "job log path")
	flag.Parse()

	log.SetOutput(os.Stdout)

	shutdownFlag = false

	// Add SIGQUIT handler (dump thread stack trace)
	quitch := make(chan os.Signal, 1)
	signal.Notify(quitch, syscall.SIGQUIT)
	go func() {
		for {
			sig := <-quitch
			log.Printf("Received signal [%v]. Calling dumpStack()\n", sig)
			go dumpStack()
		}
	}()

	dirs := []string{
		"/tmp/broker",
		"/files/classify/results",
		"/files/interior-remodel/results",
		"/files/exterior-remodel/results",
		"/files/replace/results",
		"/files/reskin/results",
		"/files/floor/results",
		"/files/wall/results",
		"/files/landscaping/results",
		"/files/paint/results",
		"/files/upscale_hat/results",
		"/files/conditioner/results",
		"/files/submit",
		"/files/shop",
	}
	for i := 0; i < len(dirs); i++ {
		if err := os.MkdirAll(dirs[i], os.ModePerm); err != nil {
			log.Fatal(err)
		}
	}

	job.Init(jobFilePtr)

	go queue.JobChecker()
	go queue.Monitor()
	go job.JobCleaner()

	nsfw.Init()
	firebase.Init()
	revenuecat.Init()

	httpd.GinInit(*selfcertPtr, *logFilePtr)

	ticker := time.NewTicker(time.Second * time.Duration(60-time.Now().Second()))
	tick := 0
	for !shutdownFlag {
		select {
		case <-ticker.C:
			if tick == 0 {
				ticker = time.NewTicker(time.Second * time.Duration(60-time.Now().Second()))
			}
			tick = tick + 1
			log.Printf(queue.CurrentStateToString(queue.CurrentState()))

			// cleanup any files over 60 minutes old
			// usually files over 10 minutes old are handled by the cron job, so this is just in case
			output, err := exec.Command("sh", "-c", "/usr/bin/find /files/ -type f -name \"*\" -mmin +60 -delete").Output()
			if err != nil {
				log.Printf("Error cleaning /files: %v\n", err)
				log.Printf("Error cleaning /files: %v\n", output)
			}

			//log.Printf(".")

		}
	}
}

// dumpStack dumps the stack trace to /tmp
func dumpStack() {
	buf := make([]byte, 1<<20)
	stacklen := runtime.Stack(buf, true)
	os.WriteFile("/tmp/stack.txt", buf[:stacklen], 0644)
	log.Printf("Printing Thread Dump...\n")
	log.Printf("\n\n%s\n\n", buf[:stacklen])
	log.Printf("Thread dump complete.\n")
}
