package loghandler

import (
	"bufio"
	"fmt"
	"jannex/log-manager/modules/config"
	"jannex/log-manager/modules/structs"
	"jannex/log-manager/modules/utils"
	"os"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

var FileMutexMap = make(map[string]*sync.Mutex)
var FileMutexMapLock sync.Mutex

func getFileMutex(filePath string) *sync.Mutex {
	FileMutexMapLock.Lock()
	defer FileMutexMapLock.Unlock()

	mutex, ok := FileMutexMap[filePath]

	if !ok {
		mutex = &sync.Mutex{}
		FileMutexMap[filePath] = mutex
	}

	return mutex
}

func AddLog(body structs.LogBody) {
	year, month, day := time.Now().Date()

	logFolder := config.Cfg.LogFolder

	utils.CreateDirectoryIfNotExists(logFolder + body.Type)

	path := logFolder + body.Type + "/" + strconv.Itoa(day) + "-" + strconv.Itoa(int(month)) + "-" + strconv.Itoa(year) + ".log"

	// get the mutex for this file
	mutex := getFileMutex(path)

	// lock the mutex to ensure the file is only opened once at a time
	mutex.Lock()
	defer mutex.Unlock()

	file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)

	if err != nil {
		fmt.Println(err)
		return
	}

	defer file.Close()

	for _, log := range body.Logs {
		if _, err := fmt.Fprintln(file, log); err != nil {
			fmt.Println(err)
		}
	}
}

func GetAvailableLogFiles(logType string) ([]string, error) {
	var availableLogs []string

	path := config.Cfg.LogFolder + logType

	files, err := os.ReadDir(path)

	if err != nil {
		fmt.Println(err)
		return []string{}, err
	}

	// sort the files by date
	sort.Slice(files, func(i, j int) bool {
		dateFormat := "2-1-2006"
		dateA, _ := time.Parse(dateFormat, strings.Split(files[i].Name(), ".")[0])
		dateB, _ := time.Parse(dateFormat, strings.Split(files[j].Name(), ".")[0])
		return dateA.After(dateB)
	})

	for _, file := range files {
		availableLogs = append(availableLogs, strings.Split(file.Name(), ".")[0])
	}

	return availableLogs, nil
}

func GetLogByDate(logType string, date string) ([]string, error) {
	var logs []string

	path := config.Cfg.LogFolder + logType + "/" + date + ".log"

	// get the mutex for this file
	mutex := getFileMutex(path)

	// lock the mutex to ensure the file is only opened once at a time
	mutex.Lock()
	defer mutex.Unlock()

	file, err := os.Open(path)
	if err != nil {
		fmt.Println(err)
		return []string{}, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)

	for scanner.Scan() {
		logs = append(logs, scanner.Text())
	}

	if len(logs) == 0 {
		return []string{}, nil
	}

	return logs, nil
}

func GetAvailableLogTypes() []string {
	var availableLogTypes []string

	files, err := os.ReadDir(config.Cfg.LogFolder)

	if err != nil {
		fmt.Println(err)
		return []string{}
	}

	for _, file := range files {
		availableLogTypes = append(availableLogTypes, file.Name())
	}

	return availableLogTypes
}
