package main

import (
	"net"
	"strings"
	"sync"
)

type Operator struct {
	ID            string
	Conn          net.Conn
	Authenticated bool
	OperatorIP    net.IPAddr
}

// Replace the map and mutex with sync.Map
var Operators sync.Map

func AuthenticateOperator(operatorConn net.Conn, serverHashedPassword string) (string, bool) {
	buffer := make([]byte, 1024)
	n, err := operatorConn.Read(buffer)
	if err != nil {
		debugLog("Error reading from client: %v", err)
		return "", false
	}
	authMessage := string(buffer[:n])

	if !strings.HasPrefix(authMessage, "AUTH:") {
		debugLog("Invalid message format")
		return "", false
	}

	creds := strings.SplitN(authMessage, ":", 3)
	if len(creds) != 3 {
		debugLog("Invalid auth message format")
		return "", false
	}
	operatorID := creds[1]
	operatorPass := creds[2]

	operatorHashedPass := HashPassword(&operatorPass)

	if operatorHashedPass == serverHashedPassword {
		infoLog("Operator %s authenticated successfully", operatorID)

		// Send success message
		operatorConn.Write([]byte("AUTH_OK"))

		// Add operator to map
		AddOperator(operatorID, operatorConn)
		return operatorID, true
	} else {
		operatorConn.Write([]byte("AUTH_FAILED"))
		infoLog("Operator %s failed authentication", operatorID)
		return "", false
	}
}

// Add operator to map
func AddOperator(operatorID string, operatorConn net.Conn) {
	// Check if operator already exists
	if _, exists := Operators.Load(operatorID); exists {
		debugLog("Operator %s already connected", operatorID)
		return
	}

	addr, ok := operatorConn.RemoteAddr().(*net.TCPAddr)
	var operatorIP net.IPAddr
	if ok {
		operatorIP = net.IPAddr{IP: addr.IP}
	} else {
		debugLog("Failed to parse IP address for operator %s", operatorID)
	}

	operator := &Operator{
		ID:            operatorID,
		Conn:          operatorConn,
		Authenticated: true,
		OperatorIP:    operatorIP,
	}

	Operators.Store(operatorID, operator)
	debugLog("Operator %s added to the list", operatorID)
}

// Delete operator on disconnect
func DeleteOperator(operatorID string) {
	// LoadAndDelete checks existence and deletes in one atomic operation
	if _, exists := Operators.LoadAndDelete(operatorID); exists {
		debugLog("Operator %s removed from the list", operatorID)
	} else {
		debugLog("Operator %s not found in list", operatorID)
	}
}

// Get operator connection by his ID
func GetOperatorConn(operatorID string) (net.Conn, bool) {
	value, exists := Operators.Load(operatorID)
	if !exists {
		debugLog("Operator %s not found", operatorID)
		return nil, false
	}

	operator := value.(*Operator)
	// debugLog("Operator found, returning his connection")
	return operator.Conn, true
}
