package main

import (
	"bytes"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

var (
	authCode string
	peers    []string
	hostID   string
)

type Message struct {
	ID           string   `json:"id"`
	Type         string   `json:"type"`
	Content      string   `json:"content"`
	VisitedNodes []string `json:"visitedNodes"`
}

func loadNodeConfig() {
	config := loadConfig()
	authCode = config.AuthCode
	peers = config.Peers
}

func generateHostID() (string, error) {
	bytes := make([]byte, 16)
	_, err := rand.Read(bytes)
	if err != nil {
		return "", fmt.Errorf("failed to generate host ID: %v", err)
	}
	return fmt.Sprintf("%x", bytes), nil
}

func sendMessage(serverAddr string, msg Message) error {
	if serverAddr == "" {
		return fmt.Errorf("server address is empty")
	}

	msgBytes, err := json.Marshal(msg)
	if err != nil {
		return fmt.Errorf("failed to marshal message: %v", err)
	}

	req, err := http.NewRequest("POST", serverAddr, bytes.NewBuffer(msgBytes))
	if err != nil {
		return fmt.Errorf("failed to create request: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", authCode)

	client := &http.Client{
		Timeout: time.Second * 10,
	}

	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("failed to send request: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := ioutil.ReadAll(resp.Body)
		return fmt.Errorf("server error: %s", body)
	}

	return nil
}

func handleNodeRequest(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
		return
	}

	auth := r.Header.Get("Authorization")
	if auth != authCode {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}

	var msg Message
	err := json.NewDecoder(r.Body).Decode(&msg)
	if err != nil {
		http.Error(w, "Error parsing JSON", http.StatusBadRequest)
		return
	}
	defer r.Body.Close()

	printDebug("Received message: %+v\n", msg)
	w.Write([]byte("Message received"))

	interpretMessage(msg)
}

func startNodeClient() {
	for {
		for _, peerAddr := range peers {
			msg := Message{
				ID:      hostID,
				Type:    "test",
				Content: "This is a test message from the client node",
			}

			err := sendMessage(peerAddr, msg)
			if err != nil {
				printWarn("Error sending message to %s: %v", peerAddr, err)
			} else {
				printInfo("Message sent successfully to: %s", peerAddr)
			}
		}
		time.Sleep(10 * time.Second)
	}
}

func interpretMessage(msg Message) {
	switch msg.Type {
	case "test":
		printDebug("Received test message: %v", msg.Content)
	case "update":
		printDebug("Received update message: %v", msg.Content)
		go update()
	case "heartbeat":
		handleHeartbeat(msg.Content)
	case "election":
		handleElection(msg.Content)
	case "search-text":
		handleSearchTextMessage(msg)
	case "search-image":
		handleSearchImageMessage(msg)
	case "search-video":
		handleSearchVideoMessage(msg)
	case "search-file":
		handleSearchFileMessage(msg)
	case "search-forum":
		handleSearchForumMessage(msg)
	case "forum-results":
		handleForumResultsMessage(msg)
	case "text-results":
		handleTextResultsMessage(msg)
	case "image-results":
		handleImageResultsMessage(msg)
	case "video-results":
		handleVideoResultsMessage(msg)
	case "file-results":
		handleFileResultsMessage(msg)
	default:
		printWarn("Received unknown message type: %v", msg.Type)
	}
}