package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"log"
	"os"
	"os/exec"
	"sync"
)

var config Config

const sockfile = "/tmp/gopaper.sock"
const pidfilePath = "/var/run/gopaper.pid"

func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	//MANAGE PIDFILES
	//check if pidfile already exists
	if _, err := os.Stat(pidfilePath); !errors.Is(err, os.ErrNotExist) {
		//if it does, kill the process and delete the pidfile
		prexPid, err := os.ReadFile(pidfilePath)
		if err != nil {
			log.Println("unable to read pre-existing pidfile", err)
			cleanExit(1)
		}
		//kill process
		err = exec.Command("kill", "-9", string(prexPid)).Run()
		if err != nil {
			log.Printf("unable to kill process %v\n", prexPid)
			cleanExit(1)
		}
		//remove pidfile
		err = os.Remove(pidfilePath)
		if err != nil {
			log.Printf("unable to remove pidfile %v\n", pidfilePath)
			cleanExit(1)
		}
	}

	//create new pidfile
	pid := os.Getpid()
	pidfile, err := os.Create(pidfilePath)
	if err != nil {
		log.Println("could not create pidfile", err)
		cleanExit(1)
	}
	buf := new(bytes.Buffer)
	err = binary.Write(buf, binary.LittleEndian, pid)
	if err != nil {
	}
	pidfile.Write(buf.Bytes())

	err = config.load()
	logfile, err := openLogfile()
	if err != nil {
		log.Println("failed to load config", err)
		cleanExit(1)
	}
	log.SetOutput(logfile)
	log.SetFlags(log.LstdFlags | log.Lshortfile | log.Lmicroseconds)
	log.Println("Welcome to GoPaper!")

	var waitGroup sync.WaitGroup
	waitGroup.Add(1)
	slideshowDir := make(chan string)

	func() {
		defer func() {
			if r := recover(); r != nil {
				log.Println("Panic recovered at top level", r)
				cleanExit(1)
			}
		}()
		go server(slideshowDir)
		go slideshow(slideshowDir)
	}()

	var dir string
	args := os.Args[1:]
	if len(args) > 0 {
		dir = args[0]
	} else {
		dir = config.Default
	}
	slideshowDir <- dir

	waitGroup.Wait()
}

func openLogfile() (*os.File, error) {
	//TODO: log rotation
	f, err := os.OpenFile(config.Cache+"/logfile", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		return nil, err
	}
	return f, nil
}

func cleanExit(code int) {
	if code == 1 {
		log.Println("shutting down gracefully after errors")
	} else {
		log.Println("shutting down gracefully")
	}

	err := os.Remove(sockfile)
	if err != nil {
		log.Printf("unable to remove sockfile at %v. Error: %v\n", sockfile, err)
	} else {
		log.Println("sockfile removed")
	}

	err = os.Remove(pidfilePath)
	if err != nil {
		log.Printf("unable to remove pidfile at %v. Error: %v\n", pidfilePath, err)
	} else {
		log.Println("pidfile removed")
	}
	os.Exit(code)
}
