package main

import (
	"fmt"
	rl "github.com/gen2brain/raylib-go/raylib"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

type App struct {
	LogPath             string
	API                 *HypixelAPI
	UUIDCache           *UUIDCache
	CurrentDisplayTable DisplayTable
}

func NewApp(apiKey string) *App {
	path := os.Getenv("USERPROFILE")
	logPath := filepath.Join(path, ".lunarclient", "offline", "multiver", "logs", "latest.log")

	return &App{
		LogPath:             logPath,
		API:                 NewHypixelAPI(apiKey),
		UUIDCache:           NewUUIDCache(120 * time.Minute),
		CurrentDisplayTable: &BedwarsDisplayTable{},
	}
}

func (a *App) Start() {

	rl.SetConfigFlags(rl.FlagWindowTransparent | rl.FlagWindowUndecorated)
	screenWidth := 800
	screenHeight := 600
	rl.InitWindow(int32(screenWidth), int32(screenHeight), "Raylib in Go")
	defer rl.CloseWindow()

	windowPosition := rl.NewVector2(500, 200)
	rl.SetWindowPosition(int(int32(windowPosition.X)), int(int32(windowPosition.Y)))

	var panOffset rl.Vector2
	var dragWindow bool = false

	const LowFps = 8
	rl.SetTargetFPS(LowFps)

	lineCh := make(chan string)
	go tailFile(a.LogPath, lineCh)

	ch := make(chan HypixelPlayerResponse)
	var wg sync.WaitGroup

	go func() {
		wg.Wait()
		close(ch)
	}()

	sx := 10
	sy := 10

	for !rl.WindowShouldClose() {
		mousePosition := rl.GetMousePosition()
		windowPosition := rl.GetWindowPosition()
		screenMousePosition := rl.Vector2{
			X: windowPosition.X + mousePosition.X,
			Y: windowPosition.Y + mousePosition.Y,
		}

		if rl.IsMouseButtonPressed(rl.MouseLeftButton) && !dragWindow {
			rl.SetTargetFPS(int32(rl.GetMonitorRefreshRate(0)))
			dragWindow = true
			panOffset.X = screenMousePosition.X - float32(windowPosition.X)
			panOffset.Y = screenMousePosition.Y - float32(windowPosition.Y)
		}

		if dragWindow {
			newWindowPositionX := int(screenMousePosition.X - panOffset.X)
			newWindowPositionY := int(screenMousePosition.Y - panOffset.Y)

			rl.SetWindowPosition(newWindowPositionX, newWindowPositionY)

			if rl.IsMouseButtonReleased(rl.MouseLeftButton) {
				dragWindow = false
				rl.SetTargetFPS(LowFps)
			}
		}

		select {
		case line := <-lineCh:
			a.onFileEmit(replaceCorruptedRune(line))
		default:
		}

		rl.BeginDrawing()
		rl.ClearBackground(rl.Color{0, 0, 0, 100})

		yOffset := sy
		for _, player := range a.CurrentDisplayTable.GetPlayers() {
			playerName := player.DisplayName
			bedwarsLevel := player.Achievements.BedwarsStar
			bedwarsWins := player.Stats.Bedwars.Wins

			rl.DrawText(fmt.Sprintf("Player: %s", playerName), int32(sx), int32(yOffset), 20, rl.Black)
			yOffset += 25
			rl.DrawText(fmt.Sprintf("Bedwars Level: %d", bedwarsLevel), int32(sx), int32(yOffset), 18, rl.DarkGray)
			yOffset += 25
			rl.DrawText(fmt.Sprintf("Bedwars Wins: %d", bedwarsWins), int32(sx), int32(yOffset), 18, rl.DarkGray)
			yOffset += 40
		}
		rl.EndDrawing()
	}
}

func (a *App) onFileEmit(line string) {
	msg := strings.TrimSpace(line)
	if len(msg) < 34 {
		return
	}
	submsg := msg[33:]
	if len(submsg) != 0 {
		LogBuf.Add(submsg)
	}

	OnlinePrefix := "[CHAT] ONLINE: "
	PartyListSeparatorLinePrefix := "[CHAT] -----------------------------------------------------"
	PartyMemberCountPrefix := "[CHAT] Party Members ("
	PartyLeaderPrefix := "[CHAT] Party Leader: "
	PartyListMembersPrefix := "[CHAT] Party Members: "

	if strings.HasPrefix(submsg, OnlinePrefix) { // Online Message
		newsubmsg := strings.TrimPrefix(submsg, OnlinePrefix)
		players := strings.Split(newsubmsg, ",")
		for _, player := range players {
			playerName := strings.TrimSpace(player)
			playerUUID, err := FetchMCPlayer(playerName)
			if err != nil {
				log.Fatalf("Error fetching UUID: %v", err)
				return
			}
			fmt.Printf("UUID of player %s: %s\n", playerName, playerUUID)
			cachedPlayer := CachedUuid{playerUUID.UUID, playerName, playerName, time.Now()}
			a.UUIDCache.Add(&cachedPlayer)

			//names, err := GetNameFromUUID(playerUUID)
			//if err != nil {
			//	log.Fatalf("Error fetching names from UUID: %v", err)
			//}
			//fmt.Printf("Name history for UUID %s: %v\n", playerUUID, names)
		}

	} else if strings.HasPrefix(submsg, PartyListSeparatorLinePrefix) { // Party List
		last, _ := LogBuf.GetSecondToLast()
		// TODO: Check if moderators
		if !strings.HasPrefix(last, PartyListMembersPrefix) {
			return
		}

		PartyMembersMsg := strings.TrimPrefix(last, PartyListMembersPrefix)
		for _, player := range strings.Split(PartyMembersMsg, ",") {
			playerName := strings.TrimSpace(strings.TrimSuffix(player, " ?"))
			if strings.HasPrefix(playerName, "[") {
				playerName = strings.Split(playerName, " ")[1]
			}
			print("Found Player: '")
			print(playerName)
			print("'\n")
			a.CurrentDisplayTable.AddPlayerN(playerName, a)

			//playerName := strings.TrimSpace(player)
			//playerUUID, err := GetUUIDFromName(playerName)
			//if err != nil {
			//	log.Fatalf("Error fetching UUID: %v", err)
			//	return
			//}
			//fmt.Printf("UUID of player %s: %s\n", playerName, playerUUID)
			//cachedPlayer := CachedUuid{playerUUID, playerName, playerName, time.Now()}
			//UuidCache.Add(&cachedPlayer)
		}

		// Parse Party Leader
		leaders_msg, err := LogBuf.GetLineStepsBack(2)
		if err != nil {
			println("Unable to find party leader message")
			return
		}
		PartyLeaderMsg := strings.TrimPrefix(leaders_msg, PartyLeaderPrefix)
		playerName := strings.TrimSpace(strings.TrimSuffix(PartyLeaderMsg, " ?"))
		if strings.HasPrefix(playerName, "[") {
			playerName = strings.Split(playerName, " ")[1]
		}
		print("Found Leader: '")
		print(playerName)
		print("'\n")
		a.CurrentDisplayTable.AddPlayerN(playerName, a)

		// Parse Party Count
		party_count_msg, err := LogBuf.GetLineStepsBack(4)
		if err != nil {
			println("Unable to find party count message")
			return
		}
		PartyCountMsg := strings.TrimPrefix(party_count_msg, PartyMemberCountPrefix)
		count_str := strings.TrimSuffix(PartyCountMsg, ")")
		count, err := strconv.Atoi(count_str)
		if err != nil {
			println("Unable to parse party count message - Invalid number used")
			return
		}
		print("Expected ")
		print(count)
		print(" party members\n")
	}

	println(submsg)
}
