<?php

namespace App\Services\Integrations;

use App\Models\Employee;
use App\Models\EmployeePresence;
use App\Models\Visit;
use App\Models\WebhookEndpoint;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class WebhookDispatcher
{
    public function dispatch(string $event, Visit $visit): void
    {
        $visit->loadMissing('organization');

        $payload = [
            'event' => $event,
            'visit' => [
                'id' => $visit->id,
                'public_id' => $visit->public_id,
                'external_ref' => $visit->external_ref,
                'source' => $visit->source,
                'status' => $visit->status,
                'visitor_type' => $visit->visitor_type,
                'badge_code' => $visit->badge_code,
                'checked_in_at' => $visit->checked_in_at?->toIso8601String(),
                'checked_out_at' => $visit->checked_out_at?->toIso8601String(),
                'visitor_name' => $visit->visitor?->full_name,
                'host_name' => $visit->host?->name,
            ],
            'timestamp' => now()->toIso8601String(),
        ];

        $this->dispatchPayload($visit->organization_id, $event, $payload);
    }

    public function dispatchEmployee(string $event, Employee $employee, ?EmployeePresence $presence = null): void
    {
        $presence ??= $employee->presence;

        $payload = [
            'event' => $event,
            'employee' => [
                'id' => $employee->id,
                'employee_code' => $employee->employee_code,
                'full_name' => $employee->full_name,
                'department' => $employee->department,
                'branch_id' => $employee->branch_id,
                'status' => $presence?->status,
                'destination' => $presence?->destination,
                'signed_in_at' => $presence?->signed_in_at?->toIso8601String(),
                'expected_return_at' => $presence?->expected_return_at?->toIso8601String(),
            ],
            'timestamp' => now()->toIso8601String(),
        ];

        $this->dispatchPayload($employee->organization_id, $event, $payload);
    }

    /** @param  array<string, mixed>  $payload */
    protected function dispatchPayload(int $organizationId, string $event, array $payload): void
    {
        $endpoints = WebhookEndpoint::query()
            ->where('organization_id', $organizationId)
            ->where('is_active', true)
            ->get()
            ->filter(fn (WebhookEndpoint $endpoint) => $endpoint->subscribesTo($event));

        foreach ($endpoints as $endpoint) {
            $this->send($endpoint, $payload);
        }
    }

    /** @param  array<string, mixed>  $payload */
    protected function send(WebhookEndpoint $endpoint, array $payload): void
    {
        $body = json_encode($payload);
        $headers = ['Content-Type' => 'application/json'];

        if ($endpoint->secret) {
            $headers['X-Frontdesk-Signature'] = hash_hmac('sha256', $body, $endpoint->secret);
        }

        try {
            Http::timeout(10)->withHeaders($headers)->withBody($body, 'application/json')->post($endpoint->url);
        } catch (\Throwable $e) {
            Log::warning('Frontdesk webhook delivery failed', [
                'endpoint_id' => $endpoint->id,
                'url' => $endpoint->url,
                'error' => $e->getMessage(),
            ]);
        }
    }
}
