package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"

	socketio "github.com/googollee/go-socket.io"
)

type UpdatePayload struct {
	Action   string `json:"action"`
	Target   string `json:"target"`
	Location string `json:"location"`
}

func registerUpdateChannel(server *socketio.Server) {

	server.OnEvent("/", "subscribe:update", func(s socketio.Conn) {
		s.Join("update")
		s.Emit("updateLogs", "👋 Subscribed to update channel")
		fmt.Println("📺", s.ID(), "joined update room")
	})

	// copy files based on the target passed over
	server.OnEvent("/", "update", func(s socketio.Conn, payload UpdatePayload) {
		switch strings.ToLower(payload.Action) {
		case "copy":
			copyLatestBuild(server, payload.Target, payload.Location)

		case "update":
			updateServer(server, payload.Target)

		default:
			server.BroadcastToRoom("/", "update", "updateLogs",
				fmt.Sprintf("❓ Unknown action: %s", payload.Action))
		}
	})

	server.OnEvent("/", "unsubscribe:update", func(s socketio.Conn) {
		s.Leave("update")
		s.Emit("updateLogs", "👋 Unsubscribed from update logs")
	})
}

func updateServer(server *socketio.Server, target string) {
	host, err := os.Hostname()
	if err != nil {
		server.BroadcastToRoom("/", "update", "updateLogs", "Could not retrieve hostname")
		return
	}
	log.Printf("Host value: [%q]", host)
	if strings.Contains(host, "VMS") || strings.Contains(host, "vms") {
		server.BroadcastToRoom("/", "update", "updateLogs", "Your are about to check for a new build and then update the server.")
		//go UpdateApp(server)
		// Kick off the update
		go func() {
			updates := UpdateApp(server) // returns <-chan string
			for msg := range updates {
				fmt.Println(msg)
				//server.BroadcastToRoom("/", "update", "updateLogs", msg)
			}

		}()

		return
	}

	if target == "" {
		server.BroadcastToRoom("/", "update", "updateLogs", "You seem to be on a dev server or not an actual production server, you MUST pass a server over. I.E. USMCD1VMS036")
		return
	} else {
		server.BroadcastToRoom("/", "update", "updateLogs", fmt.Sprintf("Running remote update on: %v", target))
		go triggerRemoteUpdate(server, target, UpdatePayload{Action: "update", Target: target})
	}
}

func copyLatestBuild(server *socketio.Server, target string, location string) {
	server.BroadcastToRoom("/", "update", "updateLogs",
		fmt.Sprintf("🚀 Copying latest build to %v", target))
	copyBuild(server, target, location)
}

func triggerRemoteUpdate(server *socketio.Server, token string, payload UpdatePayload) {

	fmt.Println("running the update process")
	basePath := "/api/controller"
	if os.Getenv("NODE_ENV") != "production" {
		basePath = "/lst/api/controller"
	}

	// send POST request with JSON, expect SSE / streaming text back
	body, _ := json.Marshal(payload)

	url := fmt.Sprintf("https://%vprod.alpla.net%v/update", token, basePath)

	if token == "test1" || token == "test2" || token == "test3" {
		url = fmt.Sprintf("https://USMCD1vms036.alpla.net/%v/update", basePath)
	}

	fmt.Println(url)
	//url := fmt.Sprintf("http://%v:8080/api/controller/update", remoteURL)
	fmt.Println(url)
	resp, err := http.Post(url, "application/json", bytes.NewBuffer(body))
	if err != nil {
		log.Println("❌ Cannot connect remote:", err)
		return
	}
	defer resp.Body.Close()

	decoder := bufio.NewReader(resp.Body)
	for {
		line, err := decoder.ReadString('\n')
		if err != nil {
			if err != io.EOF {
				log.Println("❌ Error reading stream:", err)
			}
			break
		}

		//fmt.Println(line)
		parsed := strings.TrimSpace(line)
		if parsed != "" {
			log.Println("📡 Remote log:", parsed)
			server.BroadcastToRoom("/", "update", "updateLogs", parsed)
		}
	}
}
