/*
** 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"

	"jobarranger2/src/libs/golibs/builder"
	"jobarranger2/src/libs/golibs/common"
	"jobarranger2/src/libs/golibs/config_reader/server"
	"jobarranger2/src/libs/golibs/database"
	"jobarranger2/src/libs/golibs/event"
	"jobarranger2/src/libs/golibs/logger/logger"
	"jobarranger2/src/libs/golibs/utils"
)

func ProcessDataPassing(conn database.DBConnection, eventName common.EventName, nextProcessData common.IconExecutionProcessData) error {
	var nextEventData common.EventData
	var conditions []string

	funcName := "ProcessDataPassing"

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

	nextEventData.Event.UniqueKey = common.GetUniqueKey(processName)
	nextEventData.NextProcess.Name = common.IconExecManagerProcess
	nextEventData.NextProcess.Data = nextProcessData

	if eventName == common.EventIconRetry {
		methodFlag, err := utils.GetMethodFlagFromRunJobTableByInnerJobId(conn, nextProcessData.RunJobData.InnerJobID)
		if err != nil {
			return fmt.Errorf("GetMethodFlagFromRunJobTableByInnerJobId(%d) failed. err: %w",
				nextProcessData.RunJobData.InnerJobID, err)
		}
		if methodFlag == common.MethodAbort {
			logger.JaLog("JAFLOW300008", logger.Logging{}, funcName, nextProcessData.RunJobData.InnerJobID)
			return nil
		}

		if nextProcessData.RunJobData.RetryCount < server.Options.JaIconRetry {
			// increment retry count for retry icons
			nextEventData.Event.Name = common.EventIconReady
			lockPQ, updatePQ := builder.GetRunJobRetryCountIncrementQuery(
				nextProcessData.RunJobData.InnerJobID, nextProcessData.RunJobData.RetryCount)
			nextEventData.AppendPQs(lockPQ, updatePQ)
			nextProcessData.RunJobData.RetryCount += 1
		} else {
			nextEventData.Event.Name = common.EventIconResultUpdate
			nextEventData.NextProcess.Name = common.IconResultManagerProcess
			nextProcessData.RunJobData.Status = common.StatusRunErr
			nextProcessData.JobResult.Result = common.JA_JOBRESULT_PRE_EXEC_FAIL
			switch nextProcessData.RunJobData.IconType {
			case common.IconTypeFCopy:
				nextProcessData.JobResult.Type = common.AgentJobTypePutFile
			}
		}
	} else if eventName == common.EventEndCountPlus {
		startInnerJobIdList, err := utils.GetPrevFlowJobIDList(conn, nextProcessData.RunJobData.InnerJobID)
		if err != nil {
			return fmt.Errorf("GetPrevFlowJobIDList() failed, err: [%w]", err)
		}

		result, err := MergeAfterVariablesForStartJobs(conn, startInnerJobIdList, nextProcessData.RunJobData.InnerJobID)
		if err != nil {
			return fmt.Errorf("MergeAfterVariablesForStartJobs() failed, err: [%w]", err)
		}

		conditions = append(conditions, fmt.Sprintf("inner_job_id = %d", nextProcessData.RunJobData.InnerJobID))
		count, err := utils.GetRecordCountFromTableByColumn(conn, common.Ja2RunJobVariableTable, conditions)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetRecordCountFromTableByColumn", err)
			return fmt.Errorf("GetRecordCountFromTableByColumn() failed")
		}

		nextProcessData.RunJobVariableData.SeqNo = count + 1
		nextProcessData.RunJobVariableData.InnerJobID = nextProcessData.RunJobData.InnerJobID
		nextProcessData.RunJobVariableData.InnerJobnetID = nextProcessData.RunJobData.InnerJobnetID
		nextProcessData.RunJobVariableData.BeforeVariable = result

		nextEventData.Event.Name = common.EventIconReady
		if nextProcessData.RunJobData.MethodFlag == common.MethodWait {
			logger.JaLog("JAFLOW400006", logger.Logging{}, funcName, nextProcessData.RunJobData.InnerJobID)
			nextEventData.Event.Name = common.EventIconHold
		}
		lockPQ, updatePQ := builder.GetJobStatusChangeQuery(
			nextProcessData.RunJobData.InnerJobID, common.StatusReady, -1,
			nextProcessData.RunJobData.RunCount, 0, 0)
		insertPQ, err := builder.GetRunJobVariableInsertQuery(nextProcessData.RunJobVariableData)
		if err != nil {
			return fmt.Errorf("GetRunJobVariableInsertQuery() failed, err: [%w]", err)
		}
		nextEventData.AppendPQs(lockPQ, updatePQ, insertPQ)

		sql := fmt.Sprintf(`
		SELECT COUNT(*) AS count
		FROM %s a
		WHERE a.inner_job_id = %d
		AND (
				a.status IN (%d, %d)
				OR (
					a.status = %d
					AND a.run_count = (
						SELECT MAX(run_count)
						FROM ja_2_run_job_table
						WHERE inner_job_id IN (
							SELECT start_inner_job_id
							FROM %s
							WHERE end_inner_job_id = %d
						)
					)
				)
			)
		`,
			common.Ja2RunJobTable,
			nextProcessData.RunJobData.InnerJobID,
			common.StatusRun, common.StatusAbort,
			common.StatusEnd,
			common.Ja2RunFlowTable,
			nextProcessData.RunJobData.InnerJobID,
		)
		sqlCond := builder.NewSQLCondition(sql).
			AddCondition(
				builder.NewCondition(common.ActionIgnore).
					Field("count", common.OpGt, 0).
					Build(),
			).
			DefaultAction(common.ActionExec).
			Build()
		nextEventData.SQLConditions = []common.SQLCondition{sqlCond}
	}
	nextEventData.NextProcess.Data = nextProcessData

	err := event.CreateNextEvent(
		nextEventData,
		nextProcessData.RunJobData.InnerJobnetID,
		nextProcessData.RunJobnetData.JobnetID,
		nextProcessData.RunJobData.InnerJobID)
	if err != nil {
		logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "CreateNextEvent", err)
		return fmt.Errorf("CreateNextEvent() failed")
	}
	logger.JaLog("JAFLOW400002", logger.Logging{}, funcName,
		fmt.Sprintf("inner_job_id: %d, inner_jobnet_id: %d",
			nextProcessData.RunJobData.InnerJobID,
			nextProcessData.RunJobData.InnerJobnetID))
	return nil
}
