<?php
namespace App\Http\Controllers\Api\V1;
use App\Application\Services\IdempotencyService;
use App\Application\Services\InvoiceService;
use App\Http\Controllers\Controller;
use App\Http\Requests\CreatePaymentRequest;
use App\Models\Invoice;
use App\Support\ApiResponse;
use App\Support\AtomicAmount;
use App\Support\PaymentQr;
use Illuminate\Http\Request;
use RuntimeException;
final class PaymentController extends Controller {
 public function store(CreatePaymentRequest $request,InvoiceService $invoices,IdempotencyService $idempotency){
  $merchant=$request->attributes->get('merchant');$environment=$request->attributes->get('environment');$data=$request->validated();
  try{return $idempotency->execute($request,$merchant,$environment,'payments.create',fn(string $key)=>ApiResponse::success($this->createdResource($invoices->create($merchant,$data,$environment,$key)),201));}
  catch(RuntimeException $e){if($e->getMessage()==='UNSUPPORTED_CURRENCY')return ApiResponse::error('UNSUPPORTED_CURRENCY','The requested asset or network is not enabled.',422);throw $e;}
 }
 public function index(Request $request){
  $q=Invoice::with(['asset','address'])->where('merchant_id',$request->attributes->get('merchant')->id)->where('environment',$request->attributes->get('environment'))->latest('id');
  if($request->filled('status'))$q->where('status',$request->string('status'));
  if($request->filled('order_id'))$q->where('order_id',$request->string('order_id'));
  if($request->filled('pay_currency'))$q->whereHas('asset',fn($x)=>$x->where('code',strtoupper($request->string('pay_currency'))));
  if($request->filled('created_from'))$q->where('created_at','>=',$request->date('created_from'));
  if($request->filled('created_to'))$q->where('created_at','<=',$request->date('created_to'));
  $page=$q->paginate(min(max($request->integer('per_page',20),1),100));
  return ApiResponse::success(collect($page->items())->map(fn($i)=>$this->summaryResource($i))->values(),200,['pagination'=>['page'=>$page->currentPage(),'per_page'=>$page->perPage(),'total'=>$page->total(),'last_page'=>$page->lastPage()]]);
 }
 public function show(Request $request,string $paymentId){
  $invoice=Invoice::with(['asset','address','invoiceTransactions.chainTransaction'])->where('merchant_id',$request->attributes->get('merchant')->id)->where('environment',$request->attributes->get('environment'))->where('public_id',$paymentId)->first();
  if(!$invoice)return ApiResponse::error('PAYMENT_NOT_FOUND','The requested payment does not exist.',404);
  return ApiResponse::success($this->detailResource($invoice));
 }
 public function cancel(Request $request,string $paymentId){
  $invoice=Invoice::where('merchant_id',$request->attributes->get('merchant')->id)->where('environment',$request->attributes->get('environment'))->where('public_id',$paymentId)->lockForUpdate()->first();
  if(!$invoice)return ApiResponse::error('PAYMENT_NOT_FOUND','The requested payment does not exist.',404);
  if($invoice->status!=='waiting'||$invoice->paid_amount_atomic!=='0')return ApiResponse::error('PAYMENT_NOT_CANCELLABLE','Only unpaid waiting invoices may be cancelled.',409);
  $invoice->update(['status'=>'cancelled']);return ApiResponse::success($this->summaryResource($invoice->load(['asset','address'])));
 }
 private function createdResource(Invoice $i):array{return ['payment_id'=>$i->public_id,'order_id'=>$i->order_id,'price_amount'=>number_format($i->price_amount_minor/100,2,'.',''),'price_currency'=>$i->price_currency,'pay_amount'=>AtomicAmount::toDecimal((string)$i->quoted_pay_amount_atomic,$i->asset->decimals),'pay_currency'=>$i->asset->code,'network'=>$i->asset->network,'pay_address'=>$i->address?->address,'qr_code'=>PaymentQr::forInvoice($i),'status'=>$i->status,'expires_at'=>$i->expires_at?->utc()->toIso8601String(),'checkout_url'=>rtrim(config('gateway.checkout_url'),'/').'/'.$i->public_id];}
 private function summaryResource(Invoice $i):array{return $this->createdResource($i);}
 private function detailResource(Invoice $i):array{$required=(int)($i->asset->confirmation_policy['final']??1);$txs=$i->invoiceTransactions->map(fn($it)=>['tx_hash'=>$it->chainTransaction->tx_hash,'amount'=>AtomicAmount::toDecimal((string)$it->allocated_amount_atomic,$i->asset->decimals),'confirmations'=>(int)$it->chainTransaction->confirmations,'detected_at'=>$it->chainTransaction->detected_at?->utc()->toIso8601String()])->values()->all();$confirmations=collect($txs)->min('confirmations')??0;return ['payment_id'=>$i->public_id,'order_id'=>$i->order_id,'status'=>$i->status,'pay_address'=>$i->address?->address,'qr_code'=>PaymentQr::forInvoice($i),'pay_amount'=>AtomicAmount::toDecimal((string)$i->quoted_pay_amount_atomic,$i->asset->decimals),'actually_paid'=>AtomicAmount::toDecimal((string)$i->paid_amount_atomic,$i->asset->decimals),'confirmations'=>$confirmations,'required_confirmations'=>$required,'transactions'=>$txs,'expires_at'=>$i->expires_at?->utc()->toIso8601String()];}
}
