/*
** 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"
	"os"
	"runtime/debug"

	clientcommon "jobarranger2/src/jobarg_server/managers/icon_exec_manager/workers/common"
	"jobarranger2/src/libs/golibs/common"
	"jobarranger2/src/libs/golibs/config_reader/server"
	"jobarranger2/src/libs/golibs/event"
)

var (
	runStatusChangeFlag bool
)

func endIconClient() (int, error) {

	var (
		executionData                                common.IconExecutionProcessData
		eventData                                    common.EventData
		innerJobnetMainId, innerJobnetId, innerJobId uint64
		jobnetId                                     string
		runCount, methodFlag, iconType               int
		flag                                         bool
		err                                          error
	)

	executionData, err = clientcommon.GetIconExecData()
	if err != nil {
		return common.JA_JOBEXEC_FAIL, err
	}

	// Check necessary data
	innerJobnetMainId = executionData.RunJobData.InnerJobnetMainID
	if innerJobnetMainId <= 0 {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("invalid inner_jobnet_main_id")
	}
	innerJobId = executionData.RunJobData.InnerJobID
	if innerJobId <= 0 {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("invalid inner_job_id")
	}
	runCount = executionData.RunJobData.RunCount
	if runCount < 0 {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("invalid run_count")
	}
	methodFlag = int(executionData.RunJobData.MethodFlag)
	if methodFlag < 0 {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("invalid method_flag")
	}

	// check flag file exist or not
	flag, err = event.CheckRunCountFile(clientcommon.RunCountFolderPath, innerJobnetMainId, innerJobId, runCount, methodFlag)
	if err != nil {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("failed to create flag file : %w", err)
	} else if !flag { // flag == false (nil && false)
		return common.JA_JOBEXEC_IGNORE, nil
	}

	jobnetId = executionData.RunJobnetData.JobnetID
	if jobnetId == "" {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("invalid jobnet_id")
	}
	innerJobnetId = executionData.RunJobData.InnerJobnetID
	if innerJobnetId <= 0 {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("invalid inner_jobnet_id")
	}
	innerJobId = executionData.RunJobData.InnerJobID
	if innerJobId <= 0 {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("invalid inner_job_id")
	}
	iconType = int(executionData.RunJobData.IconType)
	if iconType != int(common.IconTypeEnd) {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("invalid icon_type for end icon")
	}

	eventData = clientcommon.IconRunDataPrep(string(clientcommon.IconClientEnd), executionData)

	err = event.CreateNextEvent(eventData, innerJobnetId, jobnetId, innerJobId)
	if err != nil {
		return common.JA_JOBRESULT_PRE_EXEC_FAIL, err
	}
	runStatusChangeFlag = true
	// flag file creation
	err = event.CreateRunCountFile(clientcommon.RunCountFolderPath, innerJobnetMainId, innerJobId, runCount)
	if err != nil {
		return common.JA_JOBRESULT_FAIL, fmt.Errorf("failed to create flag file : %w", err)
	}

	return common.JA_JOBRESULT_SUCCEED, nil
}

func main() {
	var (
		err      error
		exitCode int
		pid      int
	)

	//catch runtime panic errors
	defer func() {
		if r := recover(); r != nil {
			//output stacktrace
			fmt.Fprintf(os.Stderr, "[endIconClient] Runtime panic error occurs in client. error : %s", string(debug.Stack()))
			if runStatusChangeFlag {
				os.Exit(common.JA_JOBRESULT_FAIL)
			}
			os.Exit(common.JA_JOBRESULT_PRE_EXEC_FAIL)
		}
	}()

	// add client_pid in .clientPID file
	pid = os.Getpid()
	err = common.SetClientPid(pid)
	if err != nil {
		fmt.Fprintf(os.Stderr, "[SetClientPid] %v", err)
		os.Exit(common.JA_JOBEXEC_FAIL)
	}

	err = clientcommon.ParseArgs()
	if err != nil {
		fmt.Fprintf(os.Stderr, "[ParseArgs] %v", err)
		os.Exit(common.JA_JOBEXEC_FAIL)
	}

	/*
	 // Since the client does not accept a configuration parameter,
	 // manually assign UnixSockParentDir and TmpDir.
	*/
	server.Options.UnixSockParentDir = clientcommon.UdsDirpath
	server.Options.TmpDir = clientcommon.TmpDirPath

	exitCode, err = endIconClient()
	if err != nil {
		fmt.Fprintf(os.Stderr, "[endIconClient] %v", err)
	}
	os.Exit(exitCode)
}
