/*
** 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 (
	"fmt"
	"strings"

	"jobarranger2/src/libs/golibs/common"
	"jobarranger2/src/libs/golibs/database"
	"jobarranger2/src/libs/golibs/logger/logger"
	"jobarranger2/src/libs/golibs/utils"
)

func GetHostName(hostFlag int, hostname string, processData common.FlowProcessData) (string, error) {
	funcName := "GetHostName"
	var err error
	if hostFlag != 0 {
		var prevIconData common.IconExecutionProcessData
		err = utils.Convert(processData.Data, &prevIconData)
		if err != nil {
			logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
				fmt.Errorf("conversion failed to IconExecutionProcessData, data:%v", processData.Data))
			return "", fmt.Errorf("data conversion failed")
		}
		if processData.IconType == common.IconTypeM ||
			(prevIconData.RunJobVariableData.AfterVariable == nil || string(prevIconData.RunJobVariableData.AfterVariable) == "null") {
			prevIconData.RunJobVariableData.AfterVariable = prevIconData.RunJobVariableData.BeforeVariable
		}
		var variableMap map[string]any
		variableMap, err = utils.RawJsonToMapStringAny(prevIconData.RunJobVariableData.AfterVariable)
		if err != nil {
			logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
				fmt.Errorf("conversion failed to map[string]any, data:%v", processData.Data))
			return "", fmt.Errorf("data conversion failed")
		}
		if variableMap[hostname] == nil {
			return "", nil
		}
		hostStr, ok := variableMap[hostname].(string)
		if ok {
			hostname = hostStr
		}
	}
	return hostname, nil
}

func PrepareHostInfo(conn database.DBConnection, data *common.IconExecutionProcessData) (bool, error) {
	var hostResults []common.HostResult
	var err error

	var funcName = "PrepareHostInfo"
	var disabledHost string
	activeHost := false

	iconType := data.RunJobData.IconType
	dataMap := data.RunJobData.Data

	logger.JaLog("JAFLOW400001", logger.Logging{}, funcName,
		fmt.Sprintf("inner_jobnet_id: %d, inner_job_id: %d",
			data.RunJobData.InnerJobnetID, data.RunJobData.InnerJobID))

	switch iconType {
	case common.IconTypeJob, common.IconTypeFWait, common.IconTypeReboot, common.IconTypeLess:
		if iconType == common.IconTypeLess {
			sessionFlagRaw, ok := dataMap["session_flag"]
			if !ok {
				return true, fmt.Errorf("session_flag not found in RunJobData.Data")
			}
			var sessionFlag int
			switch v := sessionFlagRaw.(type) {
			case int:
				sessionFlag = v
			case float64:
				sessionFlag = int(v)
			default:
				return true, fmt.Errorf("session_flag must be int, got %T", sessionFlagRaw)
			}

			if sessionFlag != common.JA_SES_OPERATION_FLAG_ONETIME && sessionFlag != common.JA_SES_OPERATION_FLAG_CONNECT {
				return true, nil
			}
		}

		hostname, ok := dataMap["host_name"].(string)
		if !ok || strings.TrimSpace(hostname) == "" {
			data.JobResult.Message = fmt.Sprintf("hostname considered as empty"+
				" inner_job_id [%d] job_id [%s]",
				data.RunJobData.InnerJobID, data.RunJobData.JobID)
			return activeHost, nil
		}

		hostData := common.HostData{
			Hosts: []common.HostArgs{
				{
					Hostname: hostname,
					Macroname: func() string {
						if iconType == common.IconTypeLess {
							return common.JaSSHPort
						}
						return common.JaAgentPort
					}(),
				},
			},
		}
		if hostResults, err = utils.GetHostInfo(hostData); err != nil {
			logger.JaLog("JAFLOW200010", logger.Logging{}, funcName,
				hostname, err)
			return activeHost, fmt.Errorf("GetHostIP(%s) failed", hostname)
		}
		if len(hostResults) == 1 {
			data.RunJobData.Data["host_ip"] = hostResults[0].IP
			if hostResults[0].Status == 0 {
				activeHost = true
			} else {
				disabledHost = hostResults[0].Hostname
			}
			data.RunJobData.Data["host_port"] = hostResults[0].Port
		} else {
			err = fmt.Errorf("invalid host result parameters, expected 1, received %d: %v",
				len(hostResults), hostResults)
			return activeHost, err
		}

	case common.IconTypeFCopy:
		fromHost, ok1 := dataMap["from_host_name"].(string)
		toHost, ok2 := dataMap["to_host_name"].(string)
		if !ok1 || !ok2 || strings.TrimSpace(fromHost) == "" || strings.TrimSpace(toHost) == "" {
			data.JobResult.Message = fmt.Sprintf("hostname is considered empty,"+
				" inner_job_id [%d] job_id [%s]",
				data.RunJobData.InnerJobID, data.RunJobData.JobID)
			return activeHost, nil
		}

		hostData := common.HostData{
			Hosts: []common.HostArgs{
				{
					Hostname:  fromHost,
					Macroname: common.JaAgentPort,
				},
				{
					Hostname:  toHost,
					Macroname: common.JaAgentPort,
				},
			},
		}
		if hostResults, err = utils.GetHostInfo(hostData); err != nil {
			return activeHost, fmt.Errorf("GetHostIP(%s, %s) failed, err: [%v]", fromHost, toHost, err)
		}

		if len(hostResults) == 2 {
			data.RunJobData.Data["from_host_ip"] = hostResults[0].IP
			data.RunJobData.Data["to_host_ip"] = hostResults[1].IP
			if hostResults[0].Status != 0 {
				disabledHost = hostResults[0].Hostname
			} else if hostResults[1].Status != 0 {
				disabledHost = hostResults[1].Hostname
			} else {
				activeHost = true
			}
			data.RunJobData.Data["from_host_port"] = hostResults[0].Port
			data.RunJobData.Data["to_host_port"] = hostResults[1].Port
		} else {
			err = fmt.Errorf("invalid host result parameters, expected 2, received %d: %v",
				len(hostResults), hostResults)
			return activeHost, err
		}

	default:
		//server side icons does not need host info
		return true, nil
	}
	isForce := data.RunJobData.ForceFlag == int(common.FlagOn)
	if disabledHost != "" && !isForce {
		data.JobResult.Message = fmt.Sprintf("[JAHOST200003] In %s() host is disabled: [%s]"+
			" inner_job_id [%d] job_id [%s]",
			funcName, disabledHost,
			data.RunJobData.InnerJobID, data.RunJobData.JobID)
	}
	logger.JaLog("JAFLOW400002", logger.Logging{}, funcName,
		fmt.Sprintf("inner_jobnet_id: %d, inner_job_id: %d",
			data.RunJobData.InnerJobnetID, data.RunJobData.InnerJobID))

	return activeHost, nil
}
