<?php

namespace App\Services\Settlement;

use App\Models\SettlementBatch;
use App\Lottery\SettlementBatchStatus;
use App\Services\AuditLogger;
use App\Services\LotterySettings;
use Illuminate\Support\Facades\DB;

/**
 * draw tick 在自动结算后，按系统设置自动审核并派彩入账。
 */
final class SettlementTickFinalizer
{
    public function __construct(
        private readonly SettlementBatchWorkflowService $workflow,
    ) {}

    /** @return array{approved: int, paid: int, payout_failed: int} */
    public function finalizePendingBatches(): array
    {
        $approved = 0;
        $paid = 0;
        $payoutFailed = 0;

        if (! (bool) LotterySettings::get('settlement.auto_approve_on_tick', true)) {
            return ['approved' => 0, 'paid' => 0, 'payout_failed' => 0];
        }

        $pending = SettlementBatch::query()
            ->where('status', SettlementBatchStatus::PendingReview->value)
            ->orderBy('id')
            ->limit((int) config('lottery.draw_tick_finalize_limit', 5))
            ->get();

        foreach ($pending as $batch) {
            try {
                $this->workflow->approveBySystem($batch, 'auto approve on draw tick');
                $approved++;
            } catch (\Throwable $e) {
                report($e);

                continue;
            }

            if (! (bool) LotterySettings::get('settlement.auto_payout_on_tick', true)) {
                continue;
            }

            try {
                $this->workflow->payout($batch->fresh());
                $paid++;
                AuditLogger::recordForSystem(
                    moduleCode: 'settlement',
                    actionCode: 'auto_payout',
                    targetType: 'settlement_batch',
                    targetId: (string) $batch->id,
                    afterJson: ['draw_id' => (int) $batch->draw_id],
                );
            } catch (\Throwable $e) {
                report($e);
                $this->markAutoPayoutFailed($batch, $e);
                $payoutFailed++;
            }
        }

        return ['approved' => $approved, 'paid' => $paid, 'payout_failed' => $payoutFailed];
    }

    private function markAutoPayoutFailed(SettlementBatch $batch, \Throwable $e): void
    {
        $message = mb_substr($e->getMessage(), 0, 200);

        DB::transaction(function () use ($batch, $message): void {
            $locked = SettlementBatch::query()->whereKey($batch->id)->lockForUpdate()->first();
            if ($locked === null || $locked->status !== SettlementBatchStatus::Approved->value) {
                return;
            }

            $locked->forceFill([
                'status' => SettlementBatchStatus::Failed->value,
                'review_remark' => 'auto_payout_failed: '.$message,
            ])->save();

            AuditLogger::recordForSystem(
                moduleCode: 'settlement',
                actionCode: 'auto_payout_failed',
                targetType: 'settlement_batch',
                targetId: (string) $locked->id,
                afterJson: [
                    'draw_id' => (int) $locked->draw_id,
                    'error' => $message,
                ],
            );
        });
    }
}