package main

import (
	"bufio"
	"encoding/base64"
	"encoding/json"
	"log"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"

	"SimpleArmaAdmin/internal/crypto"
	"SimpleArmaAdmin/internal/parser"
	"github.com/gorilla/websocket"
)

type DevServer struct {
	ID            string `json:"id"`
	Name          string `json:"name"`
	EncryptedRcon string `json:"encryptedRcon"`
}

type DecryptedRcon struct {
	Address string `json:"address"`
	Port    int    `json:"port"`
	Pass    string `json:"pass"`
}

func handleServerConfig(server DevServer, masterKey []byte) {
	if server.EncryptedRcon == "" {
		log.Printf("[RCON] Server %s has no RCON configuration", server.Name)
		return
	}

	// 1. Decode Base64
	encryptedBytes, err := base64.StdEncoding.DecodeString(server.EncryptedRcon)
	if err != nil {
		log.Printf("[RCON] Failed to decode RCON blob for %s: %v", server.Name, err)
		return
	}

	// 2. Decrypt using local Master Key (E2EE)
	decryptedJSON, err := crypto.Decrypt(encryptedBytes, masterKey)
	if err != nil {
		log.Printf("[RCON] Failed to decrypt RCON for %s: %v (Key mismatch?)", server.Name, err)
		return
	}

	// 3. Parse RCON parameters
	var rcon DecryptedRcon
	if err := json.Unmarshal(decryptedJSON, &rcon); err != nil {
		log.Printf("[RCON] Failed to parse decrypted RCON JSON for %s: %v", server.Name, err)
		return
	}

	log.Printf("[RCON] Successfully decrypted credentials for %s", server.Name)
	log.Printf("[RCON] Target established: %s:%d (Auth secret verified)", rcon.Address, rcon.Port)

	// TODO: Establish persistent RCON connection
}

var mockLogs = []string{
	"12:30:01.122   SCRIPT       : [RJSSupport][Chat] [Global] Zauberklöte: hi, leute kurze frage. zock seit monaten wieder mal arma, was ist aus dem gtg#4 und #5 geworden, da ist ja nix los",
	"09:37:50.865  DEFAULT      : BattlEye Server: 'Player #0 Mike1Delta (92.209.175.19:6679) connected'",
	"13:29:19.727   SCRIPT       : [RJSSupport][Chat] [Global] 纱雾.: WHAT",
	"09:38:53.842  DEFAULT      : BattlEye Server: 'Player #0 Mike1Delta disconnected'",
	"14:56:34.622   SCRIPT       : [RJSSupport][Chat] [Global] Toope: help?",
	"15:04:22.868   SCRIPT       : [RJSSupport][Chat] [Global] vatrano: Transpo 5-10min abwesend",
}

// extractPlayerName extracts the player name from event content
func extractPlayerName(content string) string {
	// For JOIN/LEAVE: "Mike1Delta connected to server"
	if strings.Contains(content, "connected to server") {
		parts := strings.Split(content, " connected")
		if len(parts) > 0 {
			return strings.TrimSpace(parts[0])
		}
	}
	if strings.Contains(content, "left the server") {
		parts := strings.Split(content, " left")
		if len(parts) > 0 {
			return strings.TrimSpace(parts[0])
		}
	}
	// For CHAT: "PlayerName: message"
	if strings.Contains(content, ":") {
		parts := strings.SplitN(content, ":", 2)
		if len(parts) > 0 {
			return strings.TrimSpace(parts[0])
		}
	}
	return ""
}

func main() {
	gatewayURL := os.Getenv("GATEWAY_URL")
	logFilePath := os.Getenv("LOG_FILE_PATH")
	mockMode := os.Getenv("MOCK_MODE") == "true"
	if logFilePath == "" {
		logFilePath = "arma_server.rpt"
	}

	masterKey := []byte("this-is-a-32-byte-master-key-xyz")
	communityID := "comm-123-abc"

	// TODO: Initialize SQLite buffer for offline mode
	// offlineBuffer, err := initOfflineBuffer("worker_buffer.db")
	// if err != nil {
	//     log.Fatalf("Failed to init offline buffer: %v", err)
	// }
	// defer offlineBuffer.Close()

	u, _ := url.Parse(gatewayURL)
	log.Printf("Worker starting for community %s. MockMode: %v, Offline-Buffer: enabled", communityID, mockMode)

	for {
		c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
		if err != nil {
			log.Printf("Dial failed: %v. Retrying in 5s...", err)
			time.Sleep(5 * time.Second)
			continue
		}

		log.Println("Connected to gateway")
		var mu sync.Mutex

		// 0. Listen for Configuration Updates (E2EE)
		go func() {
			for {
				_, message, err := c.ReadMessage()
				if err != nil {
					return
				}

				var msg struct {
					Type   string    `json:"type"`
					Server DevServer `json:"server"`
				}
				if err := json.Unmarshal(message, &msg); err == nil && msg.Type == "CONFIG_UPDATE" {
					log.Printf("[CONFIG] Received update for server: %s", msg.Server.Name)
					handleServerConfig(msg.Server, masterKey)
				}
			}
		}()

		// 1. Telemetry Loop
		go func() {
			for {
				telemetry := map[string]interface{}{
					"type":          "TELEMETRY",
					"community_id":  communityID,
					"fps":           45.5 + float64(time.Now().Unix()%5),
					"players":       12,
					"ai_count":      142 + (time.Now().Unix() % 10),
					"vehicle_count": 24,
				}
				data, _ := json.Marshal(telemetry)
				mu.Lock()
				err := c.WriteMessage(websocket.TextMessage, data)
				mu.Unlock()
				if err != nil {
					return
				}
				time.Sleep(5 * time.Second)
			}
		}()

		// 2. Log Tailing / Mocking
		go func() {
			if mockMode {
				i := 0
				for {
					line := mockLogs[i%len(mockLogs)]
					event := parser.ParseLine(line)
					if event != nil {
						event.ServerID = "server-123"
						event.ServerName = "AMS-NODE-01"

						if event.PlayerName != "" {
							event.PlayerNameHash = crypto.GenerateBlindIndex(event.PlayerName, masterKey)
						} else {
							event.PlayerName = "SYSTEM"
							event.PlayerNameHash = "system-blind-index"
						}

						payload, _ := json.Marshal(event)
						encrypted, _ := crypto.Encrypt(payload, masterKey)
						mu.Lock()
						err := c.WriteMessage(websocket.BinaryMessage, encrypted)
						mu.Unlock()
						if err != nil {
							return
						}
						log.Printf("Sent MOCK event: %s", event.Type)
					}
					i++
					time.Sleep(10 * time.Second)
				}
			} else {
				file, err := os.Open(logFilePath)
				if err != nil {
					log.Printf("Could not open log file: %v", err)
					return
				}
				file.Seek(0, 2)
				scanner := bufio.NewScanner(file)
				for {
					if scanner.Scan() {
						line := scanner.Text()
						event := parser.ParseLine(line)
						if event != nil {
							payload, _ := json.Marshal(event)
							encrypted, _ := crypto.Encrypt(payload, masterKey)
							mu.Lock()
							err := c.WriteMessage(websocket.BinaryMessage, encrypted)
							mu.Unlock()
							if err != nil {
								return
							}
							log.Printf("Sent LIVE event: %s", event.Type)
						}
					}
					time.Sleep(500 * time.Millisecond)
				}
			}
		}()

		for {
			if _, _, err := c.ReadMessage(); err != nil {
				log.Printf("Read error: %v. Reconnecting...", err)
				break
			}
		}
		c.Close()
		time.Sleep(2 * time.Second)
	}
}
