/*
** Job Arranger for ZABBIX
** Copyright (C) 2025 Daiwa Institute of Research Ltd. All Rights Reserved.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**/
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net"
	"os"
	"sync"

	utils "jobarranger2/src/jobarg_monitor/pkg/utils"
	"jobarranger2/src/libs/golibs/database"
	"jobarranger2/src/libs/golibs/uds"
)

var (
	messages []string
	msgMutex sync.Mutex
)

func runDaemon(socketPath string) {
	if _, err := os.Stat(socketPath); err == nil {
		if err := os.Remove(socketPath); err != nil {
			fmt.Fprintf(os.Stderr, "[FATAL] Failed to remove stale socket: %v\n", err)
			os.Exit(1)
		}
	}

	server, err := uds.CreateUdsServer(socketPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "[FATAL] Failed to create UDS server: %v\n", err)
		os.Exit(1)
	}
	defer server.Close()

	for {
		netConn, err := server.Accept()
		if err != nil {
			fmt.Printf("[ERROR] Accept failed: %v\n", err)
			continue
		}
		go handleClient(netConn)
	}
}

func sendMessages(conn net.Conn) {
	defer conn.Close()
	msgMutex.Lock()
	defer msgMutex.Unlock()

	if len(messages) == 0 {
		fmt.Println("No messages to send, sending empty response")
		conn.Write([]byte(""))
		return
	}

	fmt.Printf("Sending %d messages to client\n", len(messages))
	for _, msg := range messages {
		conn.Write([]byte(msg + "\n"))
	}
	messages = messages[:0]
}

func ConnectDB(args *utils.MonitorArgs) (database.DBConnection, error) {
	dbConf := database.NewDBConfig()
	dbConf.SetDBHostname(args.DBHost)
	dbConf.SetDBPort(args.DBPort)
	dbConf.SetDBName(args.DBName)
	dbConf.SetDBUser(args.DBUser)
	dbConf.SetDBPasswd(args.DBPassword)

	db, err := NewDB(dbConf)
	if err != nil {
		return nil, fmt.Errorf("%s", err.Error())
	}

	conn, err := db.GetConn()
	if err != nil {
		fmt.Fprintf(os.Stderr, "[FATAL] Failed to connect DB: %v\n", err)
		os.Exit(1)
	}
	return conn, nil
}

func handleClient(netConn net.Conn) {
	defer netConn.Close()
	buf := make([]byte, 4096)
	n, err := netConn.Read(buf)
	if err != nil && err != io.EOF {
		fmt.Printf("[ERROR] Reading from client failed: %v\n", err)
		return
	}

	if n == 0 {
		return
	}

	var clientArgs utils.MonitorArgs
	if err := json.Unmarshal(buf[:n], &clientArgs); err != nil {
		fmt.Printf("[ERROR] Failed to unmarshal args: %v\n", err)
		return
	}

	dbcon, err := ConnectDB(&clientArgs)
	if err != nil {
		appendMessage(fmt.Sprintf("[ERROR] Failed to connect DB: %v", err))
		sendMessages(netConn)
		return
	}
	defer dbcon.Close()

	if err := ProcessMonitor(dbcon, &clientArgs); err != nil {
		appendMessage(fmt.Sprintf("[ERROR] ProcessMonitor failed: %v", err))
	}
	sendMessages(netConn)
}

func appendMessage(msg string) {
	msgMutex.Lock()
	messages = append(messages, msg)
	msgMutex.Unlock()
}
