<?php
namespace App\Application\Services\Webhooks;
use App\Jobs\DeliverMerchantWebhookJob;
use App\Models\{WebhookDelivery,WebhookEndpoint};
use Illuminate\Support\Str;
final class MerchantWebhookDispatcher {
 public function dispatch(int $merchantId,string $environment,string $type,array $data,bool $testMode=false):void{
  $eventId='evt_'.Str::ulid();$payload=['id'=>$eventId,'type'=>$type,'created_at'=>now()->utc()->toIso8601String(),'test_mode'=>$testMode,'data'=>$data];$raw=json_encode($payload,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR);
  $endpoints=WebhookEndpoint::where('merchant_id',$merchantId)->where('environment',$environment)->where('status','active')->get()->filter(fn($e)=>$this->matches((array)$e->events,$type));
  foreach($endpoints as $ep){$delivery=WebhookDelivery::create(['event_id'=>$eventId,'endpoint_id'=>$ep->id,'payload'=>$payload,'raw_payload'=>$raw,'attempt_count'=>0,'status'=>'queued','next_attempt_at'=>now()]);DeliverMerchantWebhookJob::dispatch($delivery->id)->onQueue('merchant-webhooks')->afterCommit();}
 }
 private function matches(array $events,string $type):bool{if(in_array('*',$events,true)||in_array($type,$events,true))return true;foreach($events as $event){if(str_ends_with((string)$event,'.*')&&str_starts_with($type,substr((string)$event,0,-1)))return true;}return false;}
}