<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\SettlementTransaction;
use App\Models\BatJobLog;
use App\Models\Device;
use App\Jobs\ProcessSettlementJob;
use App\Services\ShjFourBService;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Queue;
use Carbon\Carbon;

/**
 * SHJ-4B チェックコマンド
 * 
 * 未処理の決済トランザクションを検索し、ProcessSettlementJobをディスパッチする兜底処理
 * 
 * 実行方法:
 * php artisan shj4b:check
 * php artisan shj4b:check --dry-run  # 実際の処理は行わず、対象のみ表示
 * php artisan shj4b:check --limit=50 # 処理件数制限
 * 
 * Cron設定例（10分毎実行）:
 * 0,10,20,30,40,50 * * * * cd /path/to/project && php artisan shj4b:check > /dev/null 2>&1
 */
class ShjFourBCheckCommand extends Command
{
    /**
     * コマンド名と説明
     *
     * @var string
     */
    protected $signature = 'shj4b:check 
                            {--dry-run : 実際の処理を行わず対象のみ表示}
                            {--limit=100 : 処理する最大件数}
                            {--hours=24 : 指定時間以内の決済のみ対象}';

    /**
     * コマンドの説明
     *
     * @var string
     */
    protected $description = 'SHJ-4B 兜底チェック - 未処理の決済トランザクションを検索してProcessSettlementJobをディスパッチ';

    /**
     * SHJ-4B サービス
     *
     * @var ShjFourBService
     */
    protected $shjFourBService;

    /**
     * コンストラクタ
     */
    public function __construct(ShjFourBService $shjFourBService)
    {
        parent::__construct();
        $this->shjFourBService = $shjFourBService;
    }

    /**
     * コマンド実行
     *
     * @return int
     */
    public function handle()
    {
        $startTime = now();
        $isDryRun = $this->option('dry-run');
        $limit = (int) $this->option('limit');
        $hours = (int) $this->option('hours');

        $this->info("SHJ-4B チェックコマンド開始");
        $this->info("実行モード: " . ($isDryRun ? "ドライラン（実際の処理なし）" : "本実行"));
        $this->info("処理制限: {$limit}件");
        $this->info("対象期間: {$hours}時間以内");

        try {
            // 未処理の決済トランザクション取得
            $unprocessedSettlements = $this->getUnprocessedSettlements($hours, $limit);

            $this->info("未処理決済トランザクション: " . $unprocessedSettlements->count() . "件");

            if ($unprocessedSettlements->isEmpty()) {
                $this->info("処理対象なし");

                // バッチログ作成 - 処理対象なし
                $this->createBatchLog('success', 0, 0, 'SHJ-4B チェック完了 - 処理対象なし');

                return 0;
            }

            // 対象一覧表示
            $this->displayTargets($unprocessedSettlements);

            if ($isDryRun) {
                $this->info("ドライランモードのため、実際の処理はスキップします");

                // バッチログ作成 - ドライラン
                $this->createBatchLog('success', 0, 0, 'SHJ-4B チェック完了 - ドライラン（' . $unprocessedSettlements->count() . '件検出）');

                return 0;
            }

            // 実際の処理実行
            $processed = $this->processSettlements($unprocessedSettlements);

            $this->info("処理完了: {$processed['success']}件成功, {$processed['failed']}件失敗");

            // バッチログ作成 - 処理完了
            $status = $processed['failed'] > 0 ? 'error' : 'success';
            $message = "SHJ-4B チェック完了 - 成功:{$processed['success']}件, 失敗:{$processed['failed']}件";
            $this->createBatchLog($status, $processed['success'], $processed['failed'], $message);

            return $processed['failed'] > 0 ? 1 : 0;

        } catch (\Throwable $e) {
            $this->error("SHJ-4B チェック処理でエラーが発生しました: " . $e->getMessage());
            Log::error('SHJ-4B チェックコマンドエラー', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            // バッチログ作成 - エラー
            $this->createBatchLog('error', 0, 1, 'SHJ-4B チェック失敗: ' . $e->getMessage());

            return 1;
        }
    }

    /**
     * 未処理の決済トランザクション取得
     *
     * @param int $hours
     * @param int $limit
     * @return \Illuminate\Database\Eloquent\Collection
     */
    private function getUnprocessedSettlements(int $hours, int $limit)
    {
        $cutoffTime = Carbon::now()->subHours($hours);

        // 条件:
        // 1. 指定時間以内に作成された
        // 2. contract_payment_numberがnullでない
        // 3. まだregular_contractのsettlement_transaction_idに関連付けられていない
        // 4. ProcessSettlementJobが実行されていない（batch_logで確認）
        $query = SettlementTransaction::where('created_at', '>=', $cutoffTime)
            ->whereNotNull('contract_payment_number')
            ->whereNotNull('pay_date')
            ->whereNotNull('settlement_amount')
            ->orderBy('created_at', 'asc');

        $settlements = $query->limit($limit)->get();

        // 既に処理済みのものを除外
        $unprocessed = $settlements->filter(function ($settlement) {
            return !$this->isAlreadyProcessed($settlement);
        });

        return $unprocessed;
    }

    /**
     * 既に処理済みかチェック
     *
     * @param SettlementTransaction $settlement
     * @return bool
     */
    private function isAlreadyProcessed(SettlementTransaction $settlement): bool
    {
        // 1. regular_contractの同一contract_payment_numberが既に処理済みかチェック
        $linkedContract = DB::table('regular_contract')
            ->where('contract_payment_number', $settlement->contract_payment_number)
            ->whereNotNull('contract_payment_day')
            ->exists();

        if ($linkedContract) {
            return true;
        }

        // 2. bat_job_logで処理完了記録があるかチェック
        $processedInBatch = BatJobLog::where('process_name', 'SHJ-4B')
            ->where('status', 'success')
            ->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%')
            ->exists();

        if ($processedInBatch) {
            return true;
        }

        // 3. 現在キューに入っているかチェック（簡易版）
        // 注: より正確にはRedis/DBキューの内容を確認する必要がある
        $recentJobDispatched = BatJobLog::where('process_name', 'SHJ-4B')
            ->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%')
            ->where('created_at', '>=', Carbon::now()->subHours(1))
            ->exists();

        return $recentJobDispatched;
    }

    /**
     * 対象一覧表示
     *
     * @param \Illuminate\Database\Eloquent\Collection $settlements
     */
    private function displayTargets($settlements)
    {
        $this->info("対象の決済トランザクション:");
        $this->table(
            ['ID', '契約支払番号', '決済金額', '支払日', '作成日時'],
            $settlements->map(function ($settlement) {
                return [
                    $settlement->settlement_transaction_id,
                    $settlement->contract_payment_number,
                    number_format($settlement->settlement_amount) . '円',
                    Carbon::parse($settlement->pay_date)->format('Y-m-d H:i:s'),
                    $settlement->created_at->format('Y-m-d H:i:s'),
                ];
            })->toArray()
        );
    }

    /**
     * 決済処理実行
     *
     * @param \Illuminate\Database\Eloquent\Collection $settlements
     * @return array
     */
    private function processSettlements($settlements): array
    {
        $success = 0;
        $failed = 0;
        $results = [];

        foreach ($settlements as $settlement) {
            try {
                $this->info("処理中: 決済トランザクションID {$settlement->settlement_transaction_id}");

                // ProcessSettlementJobをディスパッチ
                ProcessSettlementJob::dispatch(
                    $settlement->settlement_transaction_id,
                    [
                        'source' => 'shj4b_check_command',
                        'triggered_at' => now()->toISOString(),
                    ]
                );

                $success++;
                $results[] = [
                    'settlement_transaction_id' => $settlement->settlement_transaction_id,
                    'status' => 'dispatched',
                    'message' => 'ProcessSettlementJobディスパッチ成功',
                ];

                $this->info("✓ 成功: {$settlement->settlement_transaction_id}");

            } catch (\Throwable $e) {
                $failed++;
                $results[] = [
                    'settlement_transaction_id' => $settlement->settlement_transaction_id,
                    'status' => 'failed',
                    'error' => $e->getMessage(),
                ];

                $this->error("✗ 失敗: {$settlement->settlement_transaction_id} - {$e->getMessage()}");
                
                Log::error('SHJ-4B チェック 個別処理失敗', [
                    'settlement_transaction_id' => $settlement->settlement_transaction_id,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        return [
            'success' => $success,
            'failed' => $failed,
            'results' => $results,
            'total' => $settlements->count(),
        ];
    }

    /**
     * バッチログ作成 - 直接bat_job_log書き込み
     *
     * @param string $status
     * @param int $successCount
     * @param int $errorCount
     * @param string $message
     */
    private function createBatchLog(string $status, int $successCount, int $errorCount, string $message): void
    {
        try {
            $device = Device::orderBy('device_id')->first();
            $deviceId = $device ? $device->device_id : 1;

            BatJobLog::create([
                'device_id' => $deviceId,
                'process_name' => 'SHJ-4B-CHECK',
                'job_name' => 'SHJ-4Bチェックコマンド',
                'status' => $status,
                'status_comment' => $message . " (成功:{$successCount}/失敗:{$errorCount})",
                'created_at' => now()->startOfDay(),
                'updated_at' => now()->startOfDay()
            ]);

        } catch (\Exception $e) {
            Log::error('SHJ-4B-CHECK バッチログ作成エラー', [
                'error' => $e->getMessage(),
                'status' => $status,
                'message' => $message
            ]);
        }
    }
}
