<?php
namespace App\Http\Controllers\Api\V1;

use App\Contracts\SmsGateway;
use App\Domain\Transfers\Exceptions\DomainException;
use App\Enums\TransferStatus;
use App\Http\Controllers\Controller;
use App\Models\Transfer;
use App\Models\TransferEvent;
use App\Services\AuditService;
use App\Services\IdempotencyService;
use App\Services\TransferCodeService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class ResendCodeController extends Controller
{
    public function store(
        Request $request,
        Transfer $transfer,
        TransferCodeService $codes,
        IdempotencyService $idempotency,
        AuditService $audit,
    ) {
        $this->authorize('view',$transfer);
        abort_unless($transfer->send_merchant_id===$request->user()->merchant_id,403);

        return DB::transaction(function() use ($request,$transfer,$codes,$idempotency,$audit) {
            $idem=$idempotency->begin($request->user(),$request->header('Idempotency-Key'),'POST /api/v1/transfers/'.$transfer->id.'/resend-code',[]);
            if($idem['replay']) return $idem['response'];

            $locked=Transfer::whereKey($transfer->id)->lockForUpdate()->firstOrFail();
            if($locked->status!==TransferStatus::Issued){
                throw new DomainException('CODE_NOT_RESENDABLE','Only an issued transfer can receive a replacement code.',409);
            }

            $code=$codes->generate();
            $locked->code()->update([
                'code_hash'=>$code['hash'],
                'code_last4'=>$code['last4'],
                'qr_payload'=>$code['qr_payload'],
                'attempt_count'=>0,
                'locked_until'=>null,
            ]);
            TransferEvent::create(['transfer_id'=>$locked->id,'event'=>'code_issued','actor_user_id'=>$request->user()->id,'meta'=>['replacement'=>true,'code_last4'=>$code['last4']],'ip'=>$request->ip(),'created_at'=>now()]);
            $audit->record('transfer.code_rotated',$locked,[],['reference'=>$locked->reference,'code_last4'=>$code['last4']]);

            $body=['data'=>['message'=>'A replacement code was sent to the original recipient.','reference'=>$locked->reference]];
            $idempotency->finish($idem['record'],200,$body,$locked);

            DB::afterCommit(function() use ($locked,$code) {
                try {
                    app(SmsGateway::class)->send($locked->recipient_phone,'Your replacement transfer '.$locked->reference.' code is '.$code['display'].'. It expires '.$locked->expires_at->toIso8601String().'.');
                } catch (\Throwable $exception) {
                    report($exception);
                }
            });

            return $body;
        },5);
    }
}
