<?php
namespace App\Http\Controllers\Api\V1;
use App\Application\Services\{IdempotencyService,LedgerService};use App\Domain\Blockchain\Contracts\BlockchainGateway;use App\Http\Controllers\Controller;use App\Jobs\ScreenPayoutJob;use App\Models\{Asset,LedgerEntry,Payout};use App\Support\{ApiResponse,AtomicAmount};use Illuminate\Http\Request;use Illuminate\Support\Facades\DB;use Illuminate\Support\Str;
final class PayoutController extends Controller {
 public function store(Request $request,LedgerService $ledger,BlockchainGateway $gateway,IdempotencyService $idempotency){$d=$request->validate(['pay_currency'=>['required','string','max:20'],'to_address'=>['required','string','max:255'],'amount'=>['required','string','regex:/^(?:0|[1-9]\d*)(?:\.\d{1,8})?$/'],'two_factor_code'=>['required','string','size:6']]);$merchant=$request->attributes->get('merchant');$env=$request->attributes->get('environment');if(!$merchant->two_factor_enabled)return ApiResponse::error('PAYOUT_NOT_ALLOWED','Two-factor authentication is required for payouts.',409);$asset=Asset::where('code',strtoupper($d['pay_currency']))->where('enabled',true)->first();if(!$asset)return ApiResponse::error('UNSUPPORTED_CURRENCY','The requested asset or network is not enabled.',422);if(!$gateway->validateAddress($asset->network,$d['to_address']))return ApiResponse::error('PAYOUT_NOT_ALLOWED','The destination address failed network validation.',409);$atomic=AtomicAmount::fromDecimal($d['amount'],$asset->decimals);if(bccomp($atomic,(string)$asset->min_amount_atomic,0)<0)return ApiResponse::error('PAYOUT_NOT_ALLOWED','Amount is below the configured payout minimum.',409);$fee=(string)config('gateway.tron.default_fee_atomic','1000000');
  return $idempotency->execute($request,$merchant,$env,'payouts.create',function(string $key)use($merchant,$env,$asset,$d,$atomic,$fee,$ledger){$p=DB::transaction(function()use($merchant,$env,$asset,$d,$atomic,$fee,$key,$ledger){$available=$ledger->account($merchant->id,$asset->id,'merchant_available');$reserved=$ledger->account($merchant->id,$asset->id,'merchant_reserved');$balance=(string)LedgerEntry::where('account_id',$available->id)->lockForUpdate()->selectRaw("COALESCE(SUM(CASE WHEN direction='credit' THEN amount_atomic ELSE -amount_atomic END),0) as balance")->value('balance');if(bccomp($balance,$atomic,0)<0)abort(409,'Insufficient available balance.');$p=Payout::create(['public_id'=>'po_'.Str::ulid(),'merchant_id'=>$merchant->id,'environment'=>$env,'asset_id'=>$asset->id,'to_address'=>$d['to_address'],'amount_atomic'=>$atomic,'fee_atomic'=>$fee,'status'=>'pending_screening','idempotency_key'=>$key,'two_factor_confirmed_at'=>now()]);$tx=$ledger->post('payout',$p->id,"payout-reserve:{$p->id}",[['account_id'=>$available->id,'direction'=>'debit','amount_atomic'=>$atomic],['account_id'=>$reserved->id,'direction'=>'credit','amount_atomic'=>$atomic]]);$p->update(['reservation_ledger_transaction_id'=>$tx->id]);return $p;},5);ScreenPayoutJob::dispatch($p->id)->onQueue('payouts')->afterCommit();return ApiResponse::success(['payout_id'=>$p->public_id,'status'=>$p->status,'amount'=>AtomicAmount::toDecimal((string)$p->amount_atomic,$asset->decimals),'network_fee_estimate'=>AtomicAmount::toDecimal((string)$p->fee_atomic,$asset->decimals),'to_address'=>$p->to_address],202);});}
 public function index(Request $r){return ApiResponse::success(Payout::where('merchant_id',$r->attributes->get('merchant')->id)->where('environment',$r->attributes->get('environment'))->latest()->paginate(20));}
}
