<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use App\Models\Batch\BatchLog;
use App\Models\Device;

/**
 * SHJ-8 バッチ処理ログ登録コマンド
 * 
 * 統一BatchLogを使用してバッチ処理の実行ログをbatch_logテーブルに登録する
 * 仕様書に基づくSHJ-8の要求パラメータを受け取り、通用のログシステムで記録
 */
class ShjBatchLogCommand extends Command
{
    /**
     * コンソールコマンドの名前とシグネチャ
     * 
     * 引数:
     * - device_id: デバイスID (必須)
     * - process_name: プロセス名 (必須)
     * - job_name: ジョブ名 (必須)
     * - status: ステータス (必須)
     * - created_date: 登録日時 (必須、yyyy/mm/dd形式)
     * - updated_date: 更新日時 (必須、yyyy/mm/dd形式)
     *
     * @var string
     */
    protected $signature = 'shj:batch-log {device_id : デバイスID} {process_name : プロセス名} {job_name : ジョブ名} {status : ステータス} {created_date : 登録日時} {updated_date : 更新日時}';

    /**
     * コンソールコマンドの説明
     *
     * @var string
     */
    protected $description = 'SHJ-8 バッチ処理ログ登録 - バッチ処理の実行ログを登録';

    /**
     * コンストラクタ
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * コンソールコマンドを実行
     * 
     * 処理フロー:
     * 1. 入力パラメーターをチェックする
     * 2. 統一BatchLogを使用してbatch_logテーブルに記録
     * 3. 仕様書準拠の処理結果を返却する
     *
     * @return int
     */
    public function handle()
    {
        try {
            // 開始ログ出力
            $startTime = now();
            $this->info('SHJ-8 バッチ処理ログ登録を開始します。');
            
            // 引数取得
            $deviceId = (int) $this->argument('device_id');
            $processName = $this->argument('process_name');
            $jobName = $this->argument('job_name');
            $status = $this->argument('status');
            $createdDate = $this->argument('created_date');
            $updatedDate = $this->argument('updated_date');

            Log::info('SHJ-8 バッチ処理ログ登録開始', [
                'start_time' => $startTime,
                'device_id' => $deviceId,
                'process_name' => $processName,
                'job_name' => $jobName,
                'status' => $status,
                'created_date' => $createdDate,
                'updated_date' => $updatedDate
            ]);

            // 【処理1】入力パラメーターをチェックする
            $paramCheckResult = $this->validateParameters($deviceId, $processName, $jobName, $status, $createdDate, $updatedDate);
            if (!$paramCheckResult['valid']) {
                $this->error('パラメータエラー: ' . $paramCheckResult['message']);
                
                // 仕様書【判断1】パラメーターNG時の結果出力
                $this->line('処理結果: 1'); // 1 = 異常終了
                $this->line('異常情報: ' . $paramCheckResult['message']);
                
                return self::FAILURE;
            }

            // 【処理2】統一BatchLogを使用してログ登録
            $batchLog = BatchLog::createBatchLog(
                $processName, // 実際のプロセス名を使用
                $status,
                [
                    'device_id' => $deviceId,
                    'job_name' => $jobName,
                    'status_comment' => BatchLog::getSuccessComment(),
                    'input_created_date' => $createdDate,
                    'input_updated_date' => $updatedDate,
                    'shj8_params' => [
                        'device_id' => $deviceId,
                        'process_name' => $processName,
                        'job_name' => $jobName,
                        'status' => $status,
                        'created_date' => $createdDate,
                        'updated_date' => $updatedDate
                    ]
                ],
                $jobName . '：' . BatchLog::getSuccessComment()
            );

            $endTime = now();
            $this->info('SHJ-8 バッチ処理ログ登録が正常に完了しました。');
            $this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
            
            Log::info('SHJ-8 バッチ処理ログ登録完了', [
                'end_time' => $endTime,
                'duration_seconds' => $startTime->diffInSeconds($endTime),
                'batch_log_id' => $batchLog->id
            ]);

            // 仕様書【処理3】正常終了時の結果出力
            $this->line('処理結果: 0'); // 0 = 正常終了
            $this->line('異常情報: '); // 正常時は空文字

            return self::SUCCESS;

        } catch (\Exception $e) {
            $this->error('SHJ-8 バッチ処理ログ登録で予期しないエラーが発生しました: ' . $e->getMessage());
            Log::error('SHJ-8 バッチ処理ログ登録例外エラー', [
                'exception' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            // 仕様書【処理3】異常終了時の結果出力
            $this->line('処理結果: 1'); // 1 = 異常終了
            $this->line('異常情報: エラー: ' . $e->getMessage());

            return self::FAILURE;
        }
    }

    /**
     * 【処理1】パラメータの妥当性を検証
     * 
     * 仕様書に基づく検証内容:
     * - デバイスID: 必須、数値、device表に存在するか
     * - プロセス名: 「プロセス名」「ジョブ名」いずれか必須
     * - ジョブ名: 「プロセス名」「ジョブ名」いずれか必須
     * - ステータス: 必須
     * - 登録日時: 必須、yyyy/mm/dd形式
     * - 更新日時: 必須、yyyy/mm/dd形式
     *
     * @param int $deviceId デバイスID
     * @param string $processName プロセス名
     * @param string $jobName ジョブ名
     * @param string $status ステータス
     * @param string $createdDate 登録日時
     * @param string $updatedDate 更新日時
     * @return array 検証結果 ['valid' => bool, 'message' => string]
     */
    private function validateParameters(int $deviceId, string $processName, string $jobName, string $status, string $createdDate, string $updatedDate): array
    {
        // デバイスID存在チェック
        if ($deviceId <= 0) {
            return [
                'valid' => false,
                'message' => 'パラメーターNG: デバイスIDは正の整数である必要があります'
            ];
        }

        if (!Device::exists($deviceId)) {
            return [
                'valid' => false,
                'message' => "パラメーターNG: デバイスID {$deviceId} が存在しません"
            ];
        }

        // プロセス名とジョブ名のいずれか必須チェック
        if (empty($processName) && empty($jobName)) {
            return [
                'valid' => false,
                'message' => 'パラメーターNG: プロセス名またはジョブ名のいずれかは必須です'
            ];
        }

        // ステータス必須チェック
        if (empty($status)) {
            return [
                'valid' => false,
                'message' => 'パラメーターNG: ステータスは必須です'
            ];
        }

        // 日付形式チェック
        if (!$this->isValidDateFormat($createdDate)) {
            return [
                'valid' => false,
                'message' => 'パラメーターNG: 登録日時の形式が正しくありません（yyyy/mm/dd）'
            ];
        }

        if (!$this->isValidDateFormat($updatedDate)) {
            return [
                'valid' => false,
                'message' => 'パラメーターNG: 更新日時の形式が正しくありません（yyyy/mm/dd）'
            ];
        }

        return [
            'valid' => true,
            'message' => 'パラメーターチェックOK'
        ];
    }

    /**
     * 日付形式の検証
     *
     * @param string $date 日付文字列
     * @return bool 有効な日付形式かどうか
     */
    private function isValidDateFormat(string $date): bool
    {
        // yyyy/mm/dd形式の正規表現チェック
        if (!preg_match('/^\d{4}\/\d{2}\/\d{2}$/', $date)) {
            return false;
        }

        // 実際の日付として有効かチェック
        $dateParts = explode('/', $date);
        return checkdate((int)$dateParts[1], (int)$dateParts[2], (int)$dateParts[0]);
    }
}