<?php

namespace App\Http\Controllers;

use App\Models\OneCExchange;
use App\Models\OneCSetting;
use App\Models\User;
use App\Support\CrmModuleManager;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;

class OneCWebhookController extends Controller
{
    public function handle(Request $request, CrmModuleManager $moduleManager): JsonResponse
    {
        $settings = OneCSetting::query()->first();
        if (! $settings || ! $settings->is_active) {
            return response()->json(['status' => 'ignored'], 202);
        }

        $secret = (string) ($settings->webhook_secret ?? '');
        if ($secret !== '') {
            $incomingSecret = (string) ($request->header('X-CRM-Webhook-Secret', $request->input('secret', '')));
            if ($incomingSecret === '' || ! hash_equals($secret, $incomingSecret)) {
                return response()->json(['message' => 'Unauthorized'], 401);
            }
        }

        $payload = is_array($request->all()) ? $request->all() : [];
        $normalized = $this->normalizePayload($payload);

        $existing = null;
        $externalId = $normalized['external_id'] ?? null;
        if ($externalId) {
            $existing = OneCExchange::query()
                ->where('direction', (string) $normalized['direction'])
                ->where('external_id', $externalId)
                ->first();
        }

        if ($existing) {
            $normalized = $moduleManager->applyPayloadHooks('onec.exchanges.update', $normalized, [
                'hook' => 'onec.exchanges.update',
                'source' => 'webhook',
                'exchange_id' => $existing->id,
            ], array_keys($normalized));

            $existing->fill($normalized)->save();

            return response()->json(['status' => 'updated', 'id' => $existing->id]);
        }

        $normalized = $moduleManager->applyPayloadHooks('onec.exchanges.store', $normalized, [
            'hook' => 'onec.exchanges.store',
            'source' => 'webhook',
        ], array_keys($normalized));

        $exchange = OneCExchange::query()->create($normalized);

        return response()->json(['status' => 'created', 'id' => $exchange->id]);
    }

    /**
     * @param  array<string, mixed>  $payload
     * @return array<string, mixed>
     */
    private function normalizePayload(array $payload): array
    {
        $direction = strtolower(trim((string) ($payload['direction'] ?? 'inbound')));
        if (! in_array($direction, ['inbound', 'outbound'], true)) {
            $direction = 'inbound';
        }

        $entity = strtolower(trim((string) ($payload['entity'] ?? 'deals')));
        if (! in_array($entity, ['tasks', 'deals', 'companies', 'contacts', 'products', 'warehouses'], true)) {
            $entity = 'deals';
        }

        $action = strtolower(trim((string) ($payload['action'] ?? 'upsert')));
        if (! in_array($action, ['upsert', 'create', 'update', 'delete'], true)) {
            $action = 'upsert';
        }

        $status = strtolower(trim((string) ($payload['status'] ?? 'completed')));
        if (! in_array($status, ['queued', 'processing', 'completed', 'failed', 'skipped'], true)) {
            $status = 'completed';
        }

        $userId = $payload['initiated_by_user_id'] ?? $payload['user_id'] ?? null;
        if (! $userId && isset($payload['user_email'])) {
            $userId = User::query()->where('email', (string) $payload['user_email'])->value('id');
        }

        return [
            'external_id' => $this->nullableText($payload['external_id'] ?? $payload['exchange_id'] ?? $payload['id'] ?? null),
            'direction' => $direction,
            'entity' => $entity,
            'action' => $action,
            'status' => $status,
            'payload' => is_array($payload['payload'] ?? null) ? $payload['payload'] : $payload,
            'response' => is_array($payload['response'] ?? null) ? $payload['response'] : null,
            'error_message' => $this->nullableText($payload['error_message'] ?? $payload['error'] ?? null),
            'started_at' => $payload['started_at'] ?? null,
            'finished_at' => $payload['finished_at'] ?? null,
            'initiated_by_user_id' => $userId ? (int) $userId : null,
            'meta' => $this->filterMeta($payload),
        ];
    }

    /**
     * @param  array<string, mixed>  $payload
     * @return array<string, mixed>|null
     */
    private function filterMeta(array $payload): ?array
    {
        $meta = Arr::except($payload, ['secret', 'token', 'api_key', 'api_secret', 'password']);
        if ($meta === []) {
            return null;
        }

        return $meta;
    }

    private function nullableText(mixed $value): ?string
    {
        $value = trim((string) $value);

        return $value === '' ? null : $value;
    }
}

