<?php

namespace App\Services;

use App\Models\Device;
use App\Models\HardwareCheckLog;
use App\Models\PrintJobLog;
use App\Models\OperatorQue;
use App\Models\Ope;
use App\Models\Manager;
use App\Models\Setting;
use App\Models\JurisdictionParking;
use App\Models\Park;
use App\Services\ShjMailSendService;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

/**
 * SHJ-6 サーバ死活監視処理サービス
 * 
 * サーバとデバイスの死活監視、ハードウェア状態監視、プリンタログ監視を実行
 * 異常検出時のメール通知機能を含む統合モニタリングサービス
 */
class ShjSixService
{
    /**
     * ShjMailSendService
     *
     * @var ShjMailSendService
     */
    protected $mailSendService;

    /**
     * ShjEightService
     *
     * @var ShjEightService
     */
    protected $shjEightService;

    /**
     * 固定メールアドレス（DB反映NG時用）
     *
     * @var string
     */
    const FIXED_EMAIL_ADDRESS = 'test@dev-so-manager.com';

    /**
     * 監視期間（分）
     *
     * @var int
     */
    const MONITOR_PERIOD_MINUTES = 15;

    /**
     * システム監視警報用メールテンプレートID
     * 
     * @var int
     */
    const SYSTEM_ALERT_MAIL_TEMPLATE_ID = 202;

    /**
     * キュー種別定数
     */
    const QUE_CLASS_SERVER_ERROR = 101;   // サーバーエラー
    const QUE_CLASS_PRINTER_ERROR = 102;  // プリンタエラー
    const QUE_CLASS_SCANNER_ERROR = 103;  // スキャナエラー
    const QUE_CLASS_PAPER_WARNING = 104;  // プリンタ用紙残少警報

    /**
     * デバイス種別：サーバー
     */
    const DEVICE_TYPE_SERVER = 'サーバー';

    /**
     * デバイス稼働状態：稼働中
     */
    const DEVICE_WORK_ACTIVE = '1';

    /**
     * コンストラクタ
     *
     * @param ShjMailSendService $mailSendService
     * @param ShjEightService $shjEightService
     */
    public function __construct(
        ShjMailSendService $mailSendService,
        ShjEightService $shjEightService
    ) {
        $this->mailSendService = $mailSendService;
        $this->shjEightService = $shjEightService;
    }

    /**
     * SHJ-6 サーバ死活監視処理メイン実行
     * 
     * 処理フロー:
     * 【処理1】サーバ死活監視（DBアクセス）
     * 【処理2】デバイス管理マスタを取得する
     * 【処理3】デバイス毎のハードウェア状態を取得する
     * 【処理4】プリンタ制御プログラムログを取得する
     * 【処理5】バッチ処理ログを作成する
     * ※ 異常時は共通A処理を実行
     *
     * @return array 処理結果
     */
    public function executeServerMonitoring(): array
    {
        $batchLogId = null;
        $warnings = [];
        $errorDetails = [];
        $alertCount = 0;
        $totalMailSuccessCount = 0;
        $totalMailErrorCount = 0;
        $totalQueueSuccessCount = 0;  // キュー登録正常終了件数（仕様書準拠）
        $totalQueueErrorCount = 0;    // キュー登録異常終了件数（仕様書準拠）
        $accumulatedBatchComment = ''; // 累積バッチコメント
        
        try {
            // バッチ処理開始ログ（内部ログのみ、batch_log廃止）
            Log::info('SHJ-6 サーバ死活監視処理開始');

            // 【処理1】サーバ死活監視（DBアクセス）
            $dbAccessResult = $this->checkDatabaseAccessWithSettings();
            
            if (!$dbAccessResult['success']) {
                // DB接続NGの場合は共通A処理実行（キュー種別：101、DB登録可否：0）
                $commonAResult = $this->executeCommonProcessA(
                    $batchLogId,
                    'DB接続エラー: ' . $dbAccessResult['message'],
                    self::QUE_CLASS_SERVER_ERROR,
                    null,  // park_id
                    null,  // user_id
                    null,  // contract_id
                    0,     // DB登録可否=0（登録不可）
                    'サーバ死活監視：DB接続異常検出'
                );
                
                // メール送信統計を集計
                $totalMailSuccessCount += $commonAResult['mail_success_count'] ?? 0;
                $totalMailErrorCount += $commonAResult['mail_error_count'] ?? 0;
                $accumulatedBatchComment = $commonAResult['updated_batch_comment'] ?? '';
                
                return [
                    'success' => false,
                    'message' => 'データベース接続エラーが発生しました',
                    'error_details' => [$dbAccessResult['message']],
                    'batch_log_id' => $batchLogId,
                    'mail_success_count' => $totalMailSuccessCount,
                    'mail_error_count' => $totalMailErrorCount
                ];
            }

            // DB登録可否フラグを取得
            $dbRegisterFlag = $dbAccessResult['db_register_flag'];

            // 【処理2】デバイス管理マスタを取得する
            $devices = $this->getServerDevices();
            Log::info('サーバーデバイス取得完了', [
                'device_count' => count($devices)
            ]);

            // 【処理3】デバイス毎のハードウェア状態を取得する
            foreach ($devices as $device) {
                $hardwareResult = $this->checkDeviceHardwareStatus($device, $batchLogId, $dbRegisterFlag);
                if ($hardwareResult['has_alert']) {
                    $alertCount++;
                    $warnings[] = "デバイスID {$device->device_id}: ハードウェア異常検出";
                    
                    // 仕様書準拠：メール送信統計とキュー登録統計を集計
                    $totalMailSuccessCount += $hardwareResult['mail_success_count'] ?? 0;
                    $totalMailErrorCount += $hardwareResult['mail_error_count'] ?? 0;
                    $totalQueueSuccessCount += $hardwareResult['queue_success_count'] ?? 0;
                    $totalQueueErrorCount += $hardwareResult['queue_error_count'] ?? 0;
                    
                    // 仕様書準拠：バッチコメントを累積
                    if (!empty($hardwareResult['updated_batch_comment'])) {
                        $accumulatedBatchComment .= ($accumulatedBatchComment ? ' | ' : '') . 
                                                   $hardwareResult['updated_batch_comment'];
                    }
                }
            }

            // 【処理4】プリンタ制御プログラムログを取得する
            $printerResult = $this->checkPrinterErrorLogs($batchLogId, $dbRegisterFlag);
            if ($printerResult['error_count'] > 0) {
                $alertCount += $printerResult['error_count'];
                $warnings[] = "プリンタエラー {$printerResult['error_count']}件検出";
                
                // 仕様書準拠：メール送信統計とキュー登録統計を集計
                $totalMailSuccessCount += $printerResult['mail_success_count'] ?? 0;
                $totalMailErrorCount += $printerResult['mail_error_count'] ?? 0;
                $totalQueueSuccessCount += $printerResult['queue_success_count'] ?? 0;
                $totalQueueErrorCount += $printerResult['queue_error_count'] ?? 0;
                
                // 仕様書準拠：バッチコメントを累積
                if (!empty($printerResult['accumulated_batch_comment'])) {
                    $accumulatedBatchComment .= ($accumulatedBatchComment ? ' | ' : '') . 
                                               $printerResult['accumulated_batch_comment'];
                }
            }

            // 【処理5】バッチ処理ログを作成する - SHJ-8呼び出し
            // 仕様書準拠：キュー登録件数も含める
            $statusComment = sprintf(
                'デバイス数: %d, アラート件数: %d, メール正常: %d件, メール異常: %d件, キュー登録正常: %d件, キュー登録異常: %d件',
                count($devices),
                $alertCount,
                $totalMailSuccessCount,
                $totalMailErrorCount,
                $totalQueueSuccessCount,
                $totalQueueErrorCount
            );
            
            // バッチコメントが累積されている場合は追加
            if (!empty($accumulatedBatchComment)) {
                $statusComment .= ' | ' . $accumulatedBatchComment;
            }
            
            $status = 'success';  // 仕様書：常に"success"で記録
            $message = empty($warnings) ?
                'SHJ-6 サーバ死活監視処理正常完了' :
                'SHJ-6 サーバ死活監視処理完了（警告あり）';

            // 仕様書準拠：処理2で取得したデバイスIDを連結
            $deviceIds = $devices->pluck('device_id')->toArray();
            $concatenatedDeviceIds = !empty($deviceIds) ? implode(',', $deviceIds) : '';

            // SHJ-8 バッチ処理ログ作成（仕様書準拠）
            // device_id = 処理2で取得したデバイスID（複数なら連結）
            // process_name = 処理4のプロセス名（プリンタログから取得、なければ'SHJ-6'）
            // job_name = "SHJ-6サーバ死活監視" 固定
            // status = 常に "success"
            $shj8Result = $this->createShjBatchLog([
                'device_id' => $concatenatedDeviceIds,  // 処理2のデバイスID（連結）
                'process_name' => $printerResult['process_name'] ?? 'SHJ-6',  // 処理4のプロセス名
                'job_name' => 'SHJ-6サーバ死活監視',
                'status' => 'success',  // 仕様書：常にsuccess
                'status_comment' => $statusComment,
                'mail_success_count' => $totalMailSuccessCount,
                'mail_error_count' => $totalMailErrorCount,
                'queue_success_count' => $totalQueueSuccessCount,  // 仕様書準拠
                'queue_error_count' => $totalQueueErrorCount,      // 仕様書準拠
                'device_count' => count($devices),
                'alert_count' => $alertCount
            ]);
            
            // 仕様書準拠：SHJ-8の戻り値確認（処理結果 = 0以外なら異常）
            if (!$shj8Result['success']) {
                $shj8Error = $shj8Result['error'] ?? 'Unknown error';
                Log::warning('SHJ-8 バッチ処理ログ作成で異常が発生しました', [
                    'error' => $shj8Error
                ]);
                
                // 仕様書準拠：異常時はバッチコメントへ反映
                $accumulatedBatchComment .= ($accumulatedBatchComment ? ' | ' : '') . 
                                           sprintf('SHJ-8異常: %s', $shj8Error);
                
                // statusCommentも更新
                $statusComment .= sprintf(' | SHJ-8異常: %s', $shj8Error);
            }

            Log::info('SHJ-6 サーバ死活監視処理完了', [
                'status_comment' => $statusComment,
                'warnings' => $warnings,
                'alert_count' => $alertCount,
                'mail_success_count' => $totalMailSuccessCount,
                'mail_error_count' => $totalMailErrorCount
            ]);

            // 監視サマリーを生成
            $monitoringSummary = sprintf(
                '監視デバイス数: %d, アラート: %d件, メール成功: %d件',
                count($devices),
                $alertCount,
                $totalMailSuccessCount
            );

            return [
                'success' => true,
                'message' => 'SHJ-6 サーバ死活監視処理が完了しました',
                'monitoring_summary' => $monitoringSummary,
                'status_comment' => $statusComment,
                'warnings' => $warnings,
                'alert_count' => $alertCount,
                'mail_success_count' => $totalMailSuccessCount,
                'mail_error_count' => $totalMailErrorCount,
                'batch_log_id' => $batchLogId
            ];

        } catch (\Exception $e) {
            $errorMessage = 'SHJ-6 サーバ死活監視処理でエラーが発生: ' . $e->getMessage();

            // 例外発生時も共通A処理実行（キュー種別：101、DB登録可否：0）
            $commonAResult = $this->executeCommonProcessA(
                null,  // batch_log廃止のためnull
                $errorMessage,
                self::QUE_CLASS_SERVER_ERROR,
                null,
                null,
                null,
                0,
                'サーバ死活監視：システムエラー発生'
            );
            
            $totalMailSuccessCount += $commonAResult['mail_success_count'] ?? 0;
            $totalMailErrorCount += $commonAResult['mail_error_count'] ?? 0;

            Log::error('SHJ-6 サーバ死活監視処理エラー', [
                'exception' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            return [
                'success' => false,
                'message' => $errorMessage,
                'monitoring_summary' => 'エラーにより監視中断',
                'error_details' => [$e->getMessage()],
                'mail_success_count' => $totalMailSuccessCount,
                'mail_error_count' => $totalMailErrorCount
            ];
        }
    }

    /**
     * 【処理1】サーバ死活監視（DBアクセス）- 設定マスタを使用
     * 
     * @return array アクセス結果
     */
    private function checkDatabaseAccessWithSettings(): array
    {
        try {
            // 設定マスタを取得してDB接続確認
            $setting = Setting::getSettings();
            
            if (!$setting) {
                return [
                    'success' => false,
                    'message' => '設定マスタが取得できませんでした',
                    'db_register_flag' => 0
                ];
            }
            
            Log::info('データベース接続確認成功（設定マスタ取得）', [
                'setting_id' => $setting->setting_id
            ]);
            
            return [
                'success' => true,
                'message' => 'データベース接続正常',
                'db_register_flag' => 1  // DB登録可能
            ];
            
        } catch (\Exception $e) {
            Log::error('データベース接続エラー', [
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'message' => $e->getMessage(),
                'db_register_flag' => 0  // DB登録不可
            ];
        }
    }

    /**
     * 【処理2】サーバーデバイスを取得する
     * 
     * 条件:
     * - device_type = 'サーバー'
     * - device_work = '1' (稼働中)
     * - device_workstart <= 現在日付
     * - device_replace IS NULL
     * 
     * @return \Illuminate\Support\Collection デバイス情報
     */
    private function getServerDevices()
    {
        try {
            $devices = DB::table('device')
                ->select([
                    'device_id',
                    'park_id',
                    'device_type',
                    'device_subject',
                    'device_identifier',
                    'device_work',
                    'device_workstart',
                    'device_remarks'
                ])
                ->where('device_type', self::DEVICE_TYPE_SERVER)
                ->where('device_work', self::DEVICE_WORK_ACTIVE)
                ->where('device_workstart', '<=', now())
                ->whereNull('device_replace')
                ->get();

            Log::info('サーバーデバイス取得完了', [
                'device_count' => $devices->count()
            ]);

            return $devices;

        } catch (\Exception $e) {
            Log::error('サーバーデバイス取得エラー', [
                'error' => $e->getMessage()
            ]);

            throw $e;
        }
    }

    /**
     * 【処理3】デバイスのハードウェア状態をチェック
     * 
     * 直近15分のハードウェアチェックログを確認し、異常時は共通A処理を実行
     * 
     * @param object $device デバイス情報
     * @param int|null $batchLogId バッチログID
     * @param int $dbRegisterFlag DB登録可否
     * @return array チェック結果（メール送信統計含む）
     */
    private function checkDeviceHardwareStatus($device, ?int $batchLogId, int $dbRegisterFlag): array
    {
        try {
            // 直近15分のログを取得（最新1件）
            $fifteenMinutesAgo = Carbon::now()->subMinutes(self::MONITOR_PERIOD_MINUTES);
            
            $latestLog = DB::table('hardware_check_log')
                ->where('device_id', $device->device_id)
                ->where('created_at', '>=', $fifteenMinutesAgo)
                ->where('created_at', '<=', now())
                ->orderBy('created_at', 'desc')
                ->first();
            
            // ログが取得できない、または異常状態の場合
            if (!$latestLog) {
                // ログが存在しない = 異常
                $alertMessage = sprintf(
                    'ハードウェア監視異常: デバイスID=%d, デバイス名=%s, 理由=直近15分のログが存在しません',
                    $device->device_id,
                    $device->device_subject ?? 'N/A'
                );
                
                $commonAResult = $this->executeCommonProcessA(
                    $batchLogId,
                    $alertMessage,
                    self::QUE_CLASS_SERVER_ERROR,
                    $device->park_id,
                    null,  // user_id
                    null,  // contract_id
                    $dbRegisterFlag,
                    'ハードウェア監視：ログ未検出'
                );
                
                return [
                    'has_alert' => true,
                    'reason' => 'ログなし',
                    'mail_success_count' => $commonAResult['mail_success_count'] ?? 0,
                    'mail_error_count' => $commonAResult['mail_error_count'] ?? 0,
                    'queue_success_count' => $commonAResult['queue_success_count'] ?? 0,  // 仕様書準拠
                    'queue_error_count' => $commonAResult['queue_error_count'] ?? 0,      // 仕様書準拠
                    'updated_batch_comment' => $commonAResult['updated_batch_comment'] ?? ''
                ];
            }
            
            // status != 1（正常）の場合は異常
            if ($latestLog->status != HardwareCheckLog::STATUS_NORMAL) {
                $statusName = HardwareCheckLog::getStatusName($latestLog->status);
                $alertMessage = sprintf(
                    'ハードウェア監視異常: デバイスID=%d, デバイス名=%s, 状態=%s, コメント=%s',
                    $device->device_id,
                    $device->device_subject ?? 'N/A',
                    $statusName,
                    $latestLog->status_comment ?? 'N/A'
                );
                
                $commonAResult = $this->executeCommonProcessA(
                    $batchLogId,
                    $alertMessage,
                    self::QUE_CLASS_SERVER_ERROR,
                    $device->park_id,
                    null,
                    null,
                    $dbRegisterFlag,
                    'ハードウェア監視：異常状態検出'
                );
            
                return [
                    'has_alert' => true,
                    'reason' => '異常状態',
                    'mail_success_count' => $commonAResult['mail_success_count'] ?? 0,
                    'mail_error_count' => $commonAResult['mail_error_count'] ?? 0,
                    'queue_success_count' => $commonAResult['queue_success_count'] ?? 0,  // 仕様書準拠
                    'queue_error_count' => $commonAResult['queue_error_count'] ?? 0,      // 仕様書準拠
                    'updated_batch_comment' => $commonAResult['updated_batch_comment'] ?? ''
                ];
            }
            
            // 正常
            return [
                'has_alert' => false,
                'reason' => '正常',
                'mail_success_count' => 0,
                'mail_error_count' => 0
            ];
            
        } catch (\Exception $e) {
            Log::error('ハードウェア状態チェックエラー', [
                'device_id' => $device->device_id,
                'error' => $e->getMessage()
            ]);
            
            return [
                'has_alert' => false,
                'reason' => 'エラー',
                'mail_success_count' => 0,
                'mail_error_count' => 0
            ];
        }
    }

    /**
     * 【処理4】プリンタエラーログをチェック
     * 
     * 直近15分のプリンタエラーログ（status >= 100）を確認し、
     * エラーログごとに共通A処理を実行
     * 
     * 仕様書準拠：ステータス >= 100 を条件とする
     * 
     * @param int|null $batchLogId バッチログID
     * @param int $dbRegisterFlag DB登録可否
     * @return array チェック結果
     */
    private function checkPrinterErrorLogs(?int $batchLogId, int $dbRegisterFlag): array
    {
        try {
            // 直近15分のエラーログを取得
            $fifteenMinutesAgo = Carbon::now()->subMinutes(self::MONITOR_PERIOD_MINUTES);
            
            // 仕様書: ステータス >= 100
            // status は varchar型のため CAST で数値変換して比較
            $errorLogs = DB::table('print_job_log')
                ->where('created_at', '>=', $fifteenMinutesAgo)
                ->where('created_at', '<=', now())
                ->whereRaw('CAST(status AS SIGNED) >= 100')
                ->orderBy('created_at', 'desc')
                ->get();
            
            Log::info('プリンタエラーログ取得完了', [
                'error_count' => $errorLogs->count(),
                'period_minutes' => self::MONITOR_PERIOD_MINUTES
            ]);
            
            // メール送信統計とキュー登録統計（仕様書準拠）
            $mailSuccessCount = 0;
            $mailErrorCount = 0;
            $queueSuccessCount = 0;
            $queueErrorCount = 0;
            $accumulatedBatchComment = '';
            
            // エラーログごとに共通A処理を実行
            foreach ($errorLogs as $log) {
                // 仕様書準拠：statusの値に応じてキュー種別を判定
                // - status 200番台 → 102（プリンタエラー）
                // - status 300番台 → 103（スキャナエラー）
                // - status 400番台 → 104（プリンタ用紙残少警報）
                $statusValue = (int)$log->status;
                if ($statusValue >= 400 && $statusValue < 500) {
                    $queClass = self::QUE_CLASS_PAPER_WARNING;  // 104 正しい定数名
                    $errorType = 'プリンタ用紙残少警報';
                } elseif ($statusValue >= 300 && $statusValue < 400) {
                    $queClass = self::QUE_CLASS_SCANNER_ERROR;  // 103
                    $errorType = 'スキャナエラー';
                } else {
                    $queClass = self::QUE_CLASS_PRINTER_ERROR;  // 102（デフォルト）
                    $errorType = 'プリンタエラー';
                }
                
                $alertMessage = sprintf(
                    '%s: ステータス=%s, プロセス=%s, ジョブ=%s, エラーコード=%d, コメント=%s',
                    $errorType,
                    $log->status ?? 'N/A',
                    $log->process_name ?? 'N/A',
                    $log->job_name ?? 'N/A',
                    $log->error_code ?? 0,
                    $log->status_comment ?? 'N/A'
                );
                
                $commonAResult = $this->executeCommonProcessA(
                    $batchLogId,
                    $alertMessage,
                    $queClass,  // ステータス値に応じて102/103/104
                    $log->park_id,
                    $log->user_id,
                    $log->contract_id,
                    $dbRegisterFlag,
                    sprintf('プリンタ制御：%s検出', $errorType)
                );
                
                // 仕様書準拠：メール送信結果とキュー登録結果を集計
                $mailSuccessCount += $commonAResult['mail_success_count'] ?? 0;
                $mailErrorCount += $commonAResult['mail_error_count'] ?? 0;
                $queueSuccessCount += $commonAResult['queue_success_count'] ?? 0;
                $queueErrorCount += $commonAResult['queue_error_count'] ?? 0;
                
                // 仕様書準拠：バッチコメントを累積
                if (!empty($commonAResult['updated_batch_comment'])) {
                    $accumulatedBatchComment .= ($accumulatedBatchComment ? ' | ' : '') . 
                                               $commonAResult['updated_batch_comment'];
                }
            }
            
            // 仕様書準拠：処理4のプロセス名を返却（複数件を連結）
            $processNames = [];
            foreach ($errorLogs as $log) {
                if (!empty($log->process_name)) {
                    $processNames[] = $log->process_name;
                }
            }
            // 重複を除去して連結
            $processNames = array_unique($processNames);
            $concatenatedProcessNames = !empty($processNames) ? implode(',', $processNames) : null;
            
            return [
                'success' => true,
                'error_count' => $errorLogs->count(),
                'mail_success_count' => $mailSuccessCount,
                'mail_error_count' => $mailErrorCount,
                'queue_success_count' => $queueSuccessCount,  // 仕様書準拠
                'queue_error_count' => $queueErrorCount,      // 仕様書準拠
                'accumulated_batch_comment' => $accumulatedBatchComment,
                'process_name' => $concatenatedProcessNames  // 処理4のプロセス名（複数件連結）
            ];
            
        } catch (\Exception $e) {
            Log::error('プリンタエラーログチェックエラー', [
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error_count' => 0
            ];
        }
    }

    /**
     * 共通A処理：監視結果を反映
     * 
     * 仕様書準拠：
     * - SHJ-7 メール送信結果を集計（正常終了件数／異常終了件数）
     * - 異常時はバッチコメントに SHJ-7 異常情報を追記
     * - 更新されたバッチコメントでオペレータキュー登録
     * 
     * @param int|null $batchLogId バッチログID
     * @param string $alertMessage アラートメッセージ
     * @param int $queClass 対象キュー種別ID（101〜104）
     * @param int|null $parkId 駐輪場ID
     * @param int|null $userId 利用者ID
     * @param int|null $contractId 定期契約ID
     * @param int $dbRegisterFlag DB登録可否（0=不可、1=可）
     * @param string|null $batchComment バッチコメント
     * @return array 処理結果（メール送信統計含む）
     */
    private function executeCommonProcessA(
        ?int $batchLogId,
        string $alertMessage,
        int $queClass,
        ?int $parkId,
        ?int $userId,
        ?int $contractId,
        int $dbRegisterFlag,
        ?string $batchComment
    ): array {
        // メール送信結果統計
        $mailSuccessCount = 0;
        $mailErrorCount = 0;
        $mailErrorDetails = [];
        
        // キュー登録結果統計（仕様書準拠）
        $queueSuccessCount = 0;
        $queueErrorCount = 0;
        $registeredQueId = null;  // 登録したキューID（後で更新するため）
        
        try {
            Log::info('共通A処理開始', [
                'batch_log_id' => $batchLogId,
                'alert_message' => $alertMessage,
                'que_class' => $queClass,
                'park_id' => $parkId,
                'db_register_flag' => $dbRegisterFlag
            ]);

            // 【共通判断1】DB反映可否判定
            if ($dbRegisterFlag === 1) {
                // DB登録可能な場合
                
                // 仕様書準拠：バッチコメント = 処理1.定期契約ID + 元のバッチコメント
                $updatedBatchComment = sprintf(
                    '定期契約ID: %s / %s',
                    $contractId ?? 'なし',
                    $batchComment ?? ''
                );
                
                // 【共通処理1】オペレータキューを登録する（仕様書順序準拠）
                // 注：SHJ-7異常情報はメール送信後に追記
                $queueResult = $this->registerOperatorQueue(
                    $alertMessage,
                    $batchLogId,
                    $queClass,
                    $parkId,
                    $userId,
                    $contractId,
                    $updatedBatchComment
                );
                
                // 仕様書準拠：キュー登録正常終了件数／異常終了件数を更新
                if ($queueResult['success']) {
                    $queueSuccessCount++;
                    $registeredQueId = $queueResult['que_id'];  // キューIDを保存
                } else {
                    $queueErrorCount++;
                    $updatedBatchComment .= sprintf(
                        ' | キュー登録異常: %s',
                        $queueResult['error'] ?? 'Unknown error'
                    );
                }
                
                // 【共通処理2】メール送信対象オペレータを取得する
                $operators = $this->getMailTargetOperators($queClass, $parkId);
                
                // 【共通判断2】送信対象有無
                if (!empty($operators)) {
                    foreach ($operators as $operator) {
                        $result = $this->sendAlertMail($operator['email'], $alertMessage, 'オペレータ');
                        
                        // SHJ-7 メール送信結果を集計
                        if ($result['success']) {
                            $mailSuccessCount++;
                        } else {
                            $mailErrorCount++;
                            $mailErrorDetails[] = sprintf(
                                'オペレータ[%s]へのメール送信失敗: %s',
                                $operator['email'],
                                $result['error'] ?? 'Unknown error'
                            );
                        }
                    }
                }
                
                // 【共通処理3】駐輪場管理者を取得する
                $parkManagers = $this->getParkManagers($parkId);
                
                // 【共通判断3】送信対象有無
                if (!empty($parkManagers)) {
                    foreach ($parkManagers as $manager) {
                        $result = $this->sendAlertMail($manager['email'], $alertMessage, '駐輪場管理者');
                        
                        // SHJ-7 メール送信結果を集計
                        if ($result['success']) {
                            $mailSuccessCount++;
                        } else {
                            $mailErrorCount++;
                            $mailErrorDetails[] = sprintf(
                                '駐輪場管理者[%s]へのメール送信失敗: %s',
                                $manager['email'],
                                $result['error'] ?? 'Unknown error'
                            );
                        }
                    }
                }
                
                // 仕様書準拠：メール異常時にSHJ-7異常情報を追記
                if ($mailErrorCount > 0) {
                    $updatedBatchComment .= sprintf(
                        ' | SHJ-7メール異常: %d件 (%s)',
                        $mailErrorCount,
                        implode('; ', $mailErrorDetails)
                    );
                }
                
                // 仕様書準拠：キュー登録後、SHJ-7異常情報を含めてキューコメントを更新
                // キューコメント = 内部変数.バッチコメント（定期契約ID + SHJ-7異常情報）
                if ($registeredQueId && $mailErrorCount > 0) {
                    try {
                        OperatorQue::where('que_id', $registeredQueId)->update([  // 主キーはque_id
                            'que_comment' => $updatedBatchComment,  // 仕様書：キューコメントに追記
                            'updated_at' => now()
                        ]);
                        
                        Log::info('オペレータキューコメント更新完了（SHJ-7異常情報追記）', [
                            'que_id' => $registeredQueId,
                            'updated_comment' => $updatedBatchComment
                        ]);
                    } catch (\Exception $e) {
                        Log::error('オペレータキューコメント更新エラー', [
                            'que_id' => $registeredQueId,
                            'error' => $e->getMessage()
                        ]);
                    }
                }

            } else {
                // DB反映NGの場合は固定メールアドレスに緊急メール送信
                // 仕様書準拠：テンプレート不使用、件名固定、本文なし
                $result = $this->sendEmergencyMail(
                    self::FIXED_EMAIL_ADDRESS,
                    $alertMessage
                );
                
                if ($result['success']) {
                    $mailSuccessCount++;
                } else {
                    $mailErrorCount++;
                    $mailErrorDetails[] = sprintf(
                        '固定アドレス[%s]への緊急メール送信失敗: %s',
                        self::FIXED_EMAIL_ADDRESS,
                        $result['error'] ?? 'Unknown error'
                    );
                }
                
                $updatedBatchComment = $batchComment ?? '';
                if ($mailErrorCount > 0) {
                    $updatedBatchComment .= sprintf(
                        ' | 緊急メール異常: %d件 (%s)',
                        $mailErrorCount,
                        implode('; ', $mailErrorDetails)
                    );
                }
            }
            
            Log::info('共通A処理完了', [
                'batch_log_id' => $batchLogId,
                'que_class' => $queClass,
                'mail_success_count' => $mailSuccessCount,
                'mail_error_count' => $mailErrorCount,
                'queue_success_count' => $queueSuccessCount,
                'queue_error_count' => $queueErrorCount,
                'updated_batch_comment' => $updatedBatchComment ?? $batchComment
            ]);
            
            return [
                'success' => true,
                'mail_success_count' => $mailSuccessCount,
                'mail_error_count' => $mailErrorCount,
                'mail_error_details' => $mailErrorDetails,
                'queue_success_count' => $queueSuccessCount,  // 仕様書準拠
                'queue_error_count' => $queueErrorCount,      // 仕様書準拠
                'updated_batch_comment' => $updatedBatchComment ?? $batchComment
            ];
            
        } catch (\Exception $e) {
            Log::error('共通A処理エラー', [
                'batch_log_id' => $batchLogId,
                'que_class' => $queClass,
                'error' => $e->getMessage()
            ]);
            
            $updatedBatchComment = ($batchComment ?? '') . ' | 共通A処理エラー: ' . $e->getMessage();
            
            return [
                'success' => false,
                'mail_success_count' => $mailSuccessCount,
                'mail_error_count' => $mailErrorCount,
                'mail_error_details' => $mailErrorDetails,
                'queue_success_count' => $queueSuccessCount,
                'queue_error_count' => $queueErrorCount,
                'updated_batch_comment' => $updatedBatchComment,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * オペレータキューを登録
     * 
     * 仕様書準拠：
     * - 定期契約IDをバッチコメントに含める
     * - 登録の成否とque_idを返却（後で更新するため）
     * 
     * @param string $alertMessage アラートメッセージ
     * @param int|null $batchLogId バッチログID
     * @param int $queClass 対象キュー種別ID（101〜104）
     * @param int|null $parkId 駐輪場ID
     * @param int|null $userId 利用者ID
     * @param int|null $contractId 定期契約ID
     * @param string|null $batchComment バッチコメント（SHJ-7異常情報は後で追記）
     * @return array 登録結果 ['success' => bool, 'error' => string|null, 'que_id' => int|null]
     */
    private function registerOperatorQueue(
        string $alertMessage,
        ?int $batchLogId,
        int $queClass,
        ?int $parkId,
        ?int $userId,
        ?int $contractId,
        ?string $batchComment
    ): array {
        try {
            // 仕様書準拠（todo/SHJ-6/SHJ-6.txt:170-182）：
            // - キューコメント = 内部変数.バッチコメント
            // - キューステータスコメント = "" (空)
            // - 業務指示コメント = "" (空)
            
            $operatorQue = OperatorQue::create([
                'que_class' => $queClass,
                'user_id' => $userId,
                'contract_id' => $contractId,
                'park_id' => $parkId,
                'que_comment' => $batchComment ?? '',  // 仕様書：内部変数.バッチコメント（SHJ-7異常情報は後で追記）
                'que_status' => 1, // キュー発生
                'que_status_comment' => '',  // 仕様書：空文字列
                'work_instructions' => '',   // 仕様書：空文字列
                'operator_id' => 9999999,    // 仕様書準拠：固定値
                'created_at' => now(),
                'updated_at' => now()
            ]);
            
            Log::info('オペレータキュー登録完了', [
                'batch_log_id' => $batchLogId,
                'que_class' => $queClass,
                'que_id' => $operatorQue->que_id,  // 主キーはque_id
                'park_id' => $parkId,
                'user_id' => $userId,
                'contract_id' => $contractId
            ]);
            
            return [
                'success' => true,
                'error' => null,
                'que_id' => $operatorQue->que_id  // 仕様書準拠：主キーque_idを返却
            ];
            
        } catch (\Exception $e) {
            Log::error('オペレータキュー登録エラー', [
                'batch_log_id' => $batchLogId,
                'que_class' => $queClass,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => $e->getMessage(),
                'que_id' => null
            ];
        }
    }

    /**
     * メール送信対象オペレータを取得
     * 
     * 管轄駐輪場マスタをJOINして、指定駐輪場を管轄しているオペレータのみ取得
     * 
     * キュー種別IDに応じた送信フラグをチェック：
     * - 101（サーバーエラー） → ope_sendalart_que10
     * - 102（プリンタエラー） → ope_sendalart_que11
     * - 103（スキャナエラー） → ope_sendalart_que12
     * - 104（プリンタ用紙残少） → ope_sendalart_que13
     * 
     * @param int $queClass 対象キュー種別ID
     * @param int|null $parkId 駐輪場ID（nullの場合は全オペレータ）
     * @return array オペレータ一覧
     */
    private function getMailTargetOperators(int $queClass, ?int $parkId): array
    {
        try {
            // キュー種別IDに対応する送信フラグカラム名を決定
            $alertFlagColumn = $this->getOperatorAlertFlagColumn($queClass);
            
            if (empty($alertFlagColumn)) {
                Log::warning('不正なキュー種別ID', ['que_class' => $queClass]);
                return [];
            }
            
            // 管轄駐輪場マスタをJOINしてオペレータを取得
            $query = DB::table('ope as T1')
                ->select(['T1.ope_id', 'T1.ope_name', 'T1.ope_mail'])
                ->where('T1.' . $alertFlagColumn, 1)  // 該当アラート送信フラグが有効
                ->where('T1.ope_quit_flag', 0)         // 退職していない
                ->whereNotNull('T1.ope_mail')
                ->where('T1.ope_mail', '!=', '');
            
            // 駐輪場IDが指定されている場合は管轄駐輪場マスタでフィルタ
            if ($parkId !== null) {
                $query->join('jurisdiction_parking as T2', 'T1.ope_id', '=', 'T2.ope_id')
                      ->where('T2.park_id', $parkId);
            }
            
            $operators = $query->get()
                ->map(function ($ope) {
                    return [
                        'ope_id' => $ope->ope_id,
                        'name' => $ope->ope_name,
                        'email' => $ope->ope_mail
                    ];
                })
                ->toArray();
                
            Log::info('メール送信対象オペレータ取得完了', [
                'que_class' => $queClass,
                'park_id' => $parkId,
                'alert_flag_column' => $alertFlagColumn,
                'operator_count' => count($operators)
            ]);
            
            return $operators;
            
        } catch (\Exception $e) {
            Log::error('メール送信対象オペレータ取得エラー', [
                'que_class' => $queClass,
                'park_id' => $parkId,
                'error' => $e->getMessage()
            ]);
            
            return [];
        }
    }

    /**
     * キュー種別IDに対応するオペレータ送信フラグカラム名を取得
     * 
     * @param int $queClass キュー種別ID
     * @return string|null カラム名
     */
    private function getOperatorAlertFlagColumn(int $queClass): ?string
    {
        $mapping = [
            101 => 'ope_sendalart_que10',  // サーバーエラー
            102 => 'ope_sendalart_que11',  // プリンタエラー
            103 => 'ope_sendalart_que12',  // スキャナエラー
            104 => 'ope_sendalart_que13',  // プリンタ用紙残少警報
        ];
        
        return $mapping[$queClass] ?? null;
    }

    /**
     * 駐輪場管理者を取得
     * 
     * 駐輪場管理者マスタから指定駐輪場の管理者を取得：
     * - 退職フラグ = 0（在職中）
     * - メールアドレスが設定されている
     * - 所属駐輪場ID = 指定駐輪場ID
     * 
     * @param int|null $parkId 駐輪場ID（nullの場合は全管理者）
     * @return array 駐輪場管理者一覧
     */
    private function getParkManagers(?int $parkId): array
    {
        try {
            $query = Manager::active()->hasEmail();
            
            // 駐輪場IDが指定されている場合はフィルタ
            if ($parkId !== null) {
                $query->where('manager_parkid', $parkId);
            }
            
            $managers = $query->select(['manager_id', 'manager_name', 'manager_mail', 'manager_parkid'])
                ->get()
                ->map(function ($manager) {
                    return [
                        'manager_id' => $manager->manager_id,
                        'name' => $manager->manager_name,
                        'email' => $manager->manager_mail,
                        'park_id' => $manager->manager_parkid
                    ];
                })
                ->toArray();
                
            Log::info('駐輪場管理者取得完了', [
                'park_id' => $parkId,
                'manager_count' => count($managers)
            ]);
            
            return $managers;
            
        } catch (\Exception $e) {
            Log::error('駐輪場管理者取得エラー', [
                'park_id' => $parkId,
                'error' => $e->getMessage()
            ]);
            
            return [];
        }
    }

    /**
     * アラートメールを送信（SHJ-7）
     * 
     * 仕様書準拠：
     * - SHJ-7 メール送信サービスを呼び出し
     * - 戻り値（成功/失敗、異常情報）を返却
     * 
     * @param string $email メールアドレス
     * @param string $alertMessage アラートメッセージ
     * @param string $recipientType 受信者タイプ
     * @return array 送信結果 ['success' => bool, 'error' => string|null]
     */
    private function sendAlertMail(string $email, string $alertMessage, string $recipientType): array
    {
        try {
            // SHJ-7 メール送信機能を使用（メールテンプレートID=202を使用）
            $result = $this->mailSendService->executeMailSend(
                $email,
                '', // 予備メールアドレスは空
                self::SYSTEM_ALERT_MAIL_TEMPLATE_ID
            );

            // SHJ-7仕様準拠: result === 0 が正常、それ以外は異常
            if (($result['result'] ?? 1) === 0) {
                Log::info('アラートメール送信成功', [
                    'email' => $email,
                    'recipient_type' => $recipientType,
                    'alert_message' => $alertMessage
                ]);

                return [
                    'success' => true,
                    'error' => null
                ];
            } else {
                // 仕様準拠: error_info を使用
                $errorInfo = $result['error_info'] ?? 'メール送信失敗';

                Log::error('アラートメール送信失敗', [
                    'email' => $email,
                    'recipient_type' => $recipientType,
                    'error_info' => $errorInfo
                ]);

                return [
                    'success' => false,
                    'error' => $errorInfo
                ];
            }

        } catch (\Exception $e) {
            Log::error('アラートメール送信エラー', [
                'email' => $email,
                'recipient_type' => $recipientType,
                'error' => $e->getMessage()
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * DB反映不可時の緊急メール送信
     * 
     * 仕様書準拠：
     * - テンプレート不使用
     * - 件名: 「So-Manager：死活監視ＤＢアタッチエラー（SHJ-6）」固定
     * - 本文: なし（空）
     * - 固定アドレスに直接送信
     * 
     * @param string $email 送信先メールアドレス
     * @param string $alertMessage アラートメッセージ（ログ用）
     * @return array 送信結果 ['success' => bool, 'error' => string|null]
     */
    private function sendEmergencyMail(string $email, string $alertMessage): array
    {
        try {
            // 仕様書準拠：件名固定、本文なし
            $subject = 'So-Manager：死活監視ＤＢアタッチエラー（SHJ-6）';
            $body = '';  // 本文なし
            
            // Laravelの Mail facade を使用して直接送信
            \Illuminate\Support\Facades\Mail::raw($body, function ($message) use ($email, $subject) {
                $message->to($email)
                        ->subject($subject);
            });
            
            Log::info('緊急メール送信成功', [
                'email' => $email,
                'subject' => $subject,
                'alert_message' => $alertMessage
            ]);
            
            return [
                'success' => true,
                'error' => null
            ];
            
        } catch (\Exception $e) {
            Log::error('緊急メール送信エラー', [
                'email' => $email,
                'alert_message' => $alertMessage,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * 【処理5】SHJ-8 バッチ処理ログ作成
     *
     * 仕様書に基づくSHJ-8共通処理呼び出し
     *
     * @param array $statistics 処理統計情報
     * @return array 処理結果 ['success' => bool, 'error' => string|null]
     */
    private function createShjBatchLog(array $statistics): array
    {
        try {
            // 仕様書準拠のSHJ-8パラメータ設定
            // device_id: 処理2で取得したデバイスID（複数ある場合は最初のIDを使用）
            // process_name: 処理4のプロセス名
            $deviceIdString = $statistics['device_id'];  // 連結されたデバイスID文字列 "1,2,3"

            // 複数デバイスIDがある場合は最初のIDを使用（SHJ-8はint型を期待）
            $deviceIdArray = !empty($deviceIdString) ? explode(',', $deviceIdString) : [];
            $deviceId = !empty($deviceIdArray) ? (int)$deviceIdArray[0] : 1;

            $processName = $statistics['process_name'] ?? 'SHJ-6';
            $jobName = $statistics['job_name'];  // "SHJ-6サーバ死活監視" 固定
            $status = $statistics['status'];  // 常に "success"
            $statusComment = $statistics['status_comment'] ?? '';

            $createdDate = now()->format('Y/m/d');
            $updatedDate = now()->format('Y/m/d');

            Log::info('SHJ-8 バッチ処理ログ作成', [
                'device_id' => $deviceId,
                'device_id_original' => $deviceIdString,
                'process_name' => $processName,
                'job_name' => $jobName,
                'status' => $status,
                'status_comment' => $statusComment
            ]);

            // SHJ-8サービスを呼び出し
            $this->shjEightService->execute(
                $deviceId,
                $processName,
                $jobName,
                $status,
                $statusComment,
                $createdDate,
                $updatedDate
            );

            Log::info('SHJ-8 バッチ処理ログ作成完了', [
                'device_id' => $deviceId,
                'process_name' => $processName
            ]);

            return [
                'success' => true,
                'error' => null
            ];

        } catch (\Exception $e) {
            Log::error('SHJ-8 バッチ処理ログ作成エラー', [
                'error' => $e->getMessage(),
                'statistics' => $statistics
            ]);

            // 仕様書準拠：SHJ-8でエラーが発生してもメイン処理は継続
            // エラー情報を返却
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
}
