package logger

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"jannex/admin-dashboard-backend/modules/config"
	"jannex/admin-dashboard-backend/modules/structs"
	"jannex/admin-dashboard-backend/modules/utils"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
)

var systemLanguageLogMessages []structs.LanguageLogMessages
var grouptasksLanguageLogMessages []structs.LanguageLogMessages

func InitLogger() {
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

	if config.Cfg.Debug {
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	} else {
		zerolog.SetGlobalLevel(zerolog.InfoLevel)
	}

	if config.Cfg.ColorizedOutput {
		log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "15:04:05"})
	}
}

func AddSystemLog(logMessage structs.LogMessage) {
	addLog(logMessage, true)
}

func AddGroupTasksLog(logMessage structs.LogMessage) {
	addLog(logMessage, false)
}

func addLog(logMessage structs.LogMessage, systemLog bool) {
	year, month, day := time.Now().Date()

	path := config.Cfg.FolderPaths.LogsSystem

	if !systemLog {
		path = config.Cfg.FolderPaths.LogsGroupTasks
	}

	f, err := os.OpenFile(path+strconv.Itoa(day)+"-"+strconv.Itoa(int(month))+"-"+strconv.Itoa(year)+".json", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)

	if err != nil {
		log.Error().Msgf("Failed to open log file %s", err.Error())
		return
	}

	defer f.Close()

	logMessage.Time = time.Now()

	file, _ := json.Marshal(logMessage)

	if _, err = fmt.Fprintln(f, string(file)); err != nil {
		log.Error().Msgf("Failed to write to log file %s", err.Error())
	}
}

func ReadLogs(date string, systemLogs bool, language string) []structs.LogMessageResponse {
	path := config.Cfg.FolderPaths.LogsSystem

	if !systemLogs {
		path = config.Cfg.FolderPaths.LogsGroupTasks
	}

	file, err := os.Open(path + date + ".json")

	if err != nil {
		log.Error().Msgf("Failed to read log file %s", err.Error())
		return nil
	}

	defer file.Close()

	fileScanner := bufio.NewScanner(file)

	var logMessages []structs.LogMessageResponse

	for fileScanner.Scan() {
		var logMessage structs.LogMessage

		if err := json.Unmarshal(fileScanner.Bytes(), &logMessage); err != nil {
			log.Error().Msgf("Failed to unmarshal log message %v", err.Error())
		}

		var languageLogMessages []structs.LanguageLogMessages

		if systemLogs {
			languageLogMessages = systemLanguageLogMessages
		} else {
			languageLogMessages = grouptasksLanguageLogMessages
		}

		logMessages = append(logMessages, getLogMessage(languageLogMessages, logMessage, language))
	}

	if err := fileScanner.Err(); err != nil {
		log.Error().Msgf("Error while reading file: %s", err)
		return nil
	}

	return logMessages
}

func getLogMessage(languageLogMessages []structs.LanguageLogMessages, logMessage structs.LogMessage, language string) structs.LogMessageResponse {
	logMessageResponse := structs.LogMessageResponse{
		Time:    logMessage.Time,
		Type:    logMessage.Type,
		LogData: logMessage.Messages,
	}

	for _, systemLanguageLogMessage := range languageLogMessages {
		if logMessage.Id == systemLanguageLogMessage.Id {
			logMessageResponse.Message = getLogLanguageMessage(systemLanguageLogMessage.Languages, language)

			return logMessageResponse
		}
	}

	return logMessageResponse
}

func getLogLanguageMessage(languages []structs.LanguageLogMessagesLanguage, language string) string {
	englishIndex := 0

	for i, l := range languages {
		if l.Lang == language {
			return l.Message
		}

		if l.Lang == "en" {
			englishIndex = i
		}
	}

	return languages[englishIndex].Message
}

func GetAllLogMessagesDates(systemLogs bool) []string {
	path := config.Cfg.FolderPaths.LogsSystem

	if !systemLogs {
		path = config.Cfg.FolderPaths.LogsGroupTasks
	}

	files, err := ioutil.ReadDir(path)

	if err != nil {
		log.Error().Msgf("Failed to read log messages directory %s", err.Error())
		return []string{}
	}

	var dates []string

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

	layout := "2-1-2006"
	parsedDates := make([]time.Time, len(dates))

	for i, dateStr := range dates {
		parsedDate, err := time.Parse(layout, dateStr)
		if err != nil {
			log.Error().Msgf("Failed to parse date %s", err.Error())
			return []string{}
		}

		parsedDates[i] = parsedDate
	}

	sort.Slice(parsedDates, func(i, j int) bool {
		return parsedDates[i].Before(parsedDates[j])
	})

	sortedDates := []string{}

	for _, date := range parsedDates {
		sortedDates = append(sortedDates, date.Format(layout))
	}

	return sortedDates
}

func InitLanguageLogMessages() {
	readLanguageLogMessages(true)
	readLanguageLogMessages(false)

	AddSystemLog(structs.LogMessage{
		Id:   8,
		Type: utils.LogTypeInfo,
	})

	AddGroupTasksLog(structs.LogMessage{
		Id:   6,
		Type: utils.LogTypeInfo,
	})
}

func readLanguageLogMessages(systemLogs bool) {
	path := config.Cfg.LogLanguageSystem

	if !systemLogs {
		path = config.Cfg.LogLanguageGroupTasks
	}

	content, err := os.ReadFile(path)

	if err != nil {
		panic("Could not read language log messages: " + err.Error())
	}

	var langLogMessages []structs.LanguageLogMessages

	if err = json.Unmarshal(content, &langLogMessages); err != nil {
		panic("Failed to unmarshal: " + err.Error())
	}

	if systemLogs {
		systemLanguageLogMessages = langLogMessages
	} else {
		grouptasksLanguageLogMessages = langLogMessages
	}
}
