<?php

namespace Licenzo\Http\Controller\Api\V1;

use Licenzo\Framework\Http\Request;
use Licenzo\Helper\Settings;
use Licenzo\Model\SubscriptionTransaction;
use Licenzo\Model\WebhookLog;
use Licenzo\Services\IdempotencyService;
use Licenzo\Modules\WooCommerce\WooOrderService;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

class WebhookController
{
    public function woocommerce(Request $request)
    {
        $payload = $request->all();
        $rawBody = $request->rawBody();
        if ($rawBody === '') {
            $rawBody = wp_json_encode($payload);
        }
        $headers = $request->header();

        $eventType = (string) ($payload['event'] ?? $payload['type'] ?? 'woocommerce.webhook');
        $eventId = (string) ($payload['id'] ?? $payload['event_id'] ?? $payload['resource_id'] ?? '');
        $orderId = isset($payload['order_id']) ? (int) $payload['order_id'] : 0;

        $webhookLog = WebhookLog::create([
            'provider' => WebhookLog::PROVIDER_WOOCOMMERCE,
            'event_type' => $eventType,
            'event_id' => $eventId ?: null,
            'payload' => $payload,
            'headers' => $headers,
            'status' => WebhookLog::STATUS_PENDING,
        ]);

        if (!$this->verifySignature($request, $rawBody)) {
            $webhookLog->markAsFailed('Invalid signature');
            return [
                'success' => false,
                'message' => 'Invalid signature',
                'status' => 401,
            ];
        }

        if (!$this->verifyTimestamp($request, $payload)) {
            $webhookLog->markAsFailed('Webhook timestamp outside tolerance');
            return [
                'success' => false,
                'message' => 'Webhook timestamp outside tolerance',
                'status' => 401,
            ];
        }

        if ($orderId <= 0) {
            $webhookLog->markAsFailed('order_id missing');
            return [
                'success' => false,
                'message' => 'Missing order_id',
                'status' => 422,
            ];
        }

        $eventScope = 'woo_webhook_event';
        $eventKey = $eventId !== '' ? $eventId : ('order_' . $orderId . '_' . md5($rawBody));

        $idempotency = new IdempotencyService();
        $reserved = $idempotency->acquire(
            SubscriptionTransaction::PROVIDER_WOOCOMMERCE,
            $eventScope,
            $eventKey,
            null,
            null,
            hash('sha256', $rawBody),
            gmdate('Y-m-d H:i:s', strtotime('+30 days'))
        );

        if (!$reserved) {
            $webhookLog->markAsProcessed();
            return [
                'success' => true,
                'message' => 'Duplicate webhook ignored',
                'duplicate' => true,
            ];
        }

        try {
            (new WooOrderService())->process($orderId);
            $idempotency->markProcessed(SubscriptionTransaction::PROVIDER_WOOCOMMERCE, $eventScope, $eventKey);
            $webhookLog->markAsProcessed();

            return [
                'success' => true,
                'message' => 'Webhook processed',
                'order_id' => $orderId,
            ];
        } catch (\Throwable $e) {
            $idempotency->markFailed(SubscriptionTransaction::PROVIDER_WOOCOMMERCE, $eventScope, $eventKey);
            $webhookLog->markAsFailed($e->getMessage());

            return [
                'success' => false,
                'message' => 'Webhook processing failed',
                'status' => 500,
            ];
        }
    }

    private function verifySignature(Request $request, string $rawBody): bool
    {
        $secret = (string) Settings::get('webhook_settings.woo_secret', '');
        if ($secret === '') {
            $secret = defined('LICENZO_WEBHOOK_SECRET') ? (string) LICENZO_WEBHOOK_SECRET : '';
        }

        if ($secret === '') {
            return false;
        }

        $headers = $request->header();
        $signature = $this->extractSignature($headers);
        if ($signature === '') {
            return false;
        }

        if ($rawBody === '') {
            return false;
        }

        $normalizedSignature = $this->normalizeSignature($signature);
        $expectedHex = hash_hmac('sha256', $rawBody, $secret);
        $expectedB64 = base64_encode(hash_hmac('sha256', $rawBody, $secret, true));

        return hash_equals($expectedHex, $normalizedSignature) || hash_equals($expectedB64, $normalizedSignature);
    }

    private function extractSignature(array $headers): string
    {
        $candidates = [
            'X-Licenzo-Signature',
            'x-licenzo-signature',
            'X-Wc-Webhook-Signature',
            'x-wc-webhook-signature',
            'X-WC-Webhook-Signature',
        ];

        foreach ($candidates as $candidate) {
            if (!isset($headers[$candidate])) {
                continue;
            }

            $value = $headers[$candidate];
            if (is_array($value)) {
                $value = (string) reset($value);
            }

            $signature = trim((string) $value);
            if ($signature !== '') {
                return $signature;
            }
        }

        return '';
    }

    private function normalizeSignature(string $signature): string
    {
        $trimmed = trim($signature);
        if (str_starts_with($trimmed, 'sha256=')) {
            return substr($trimmed, 7);
        }

        return $trimmed;
    }

    private function verifyTimestamp(Request $request, array $payload): bool
    {
        $timestamp = $this->extractTimestamp($request->header(), $payload);
        if ($timestamp === null) {
            // WooCommerce does not always provide a timestamp; rely on idempotency if absent.
            return true;
        }

        $tolerance = (int) Settings::get('webhook_settings.tolerance_seconds', 300);
        if ($tolerance <= 0) {
            $tolerance = 300;
        }

        return abs(time() - $timestamp) <= $tolerance;
    }

    private function extractTimestamp(array $headers, array $payload): ?int
    {
        $headerCandidates = [
            'X-Licenzo-Timestamp',
            'x-licenzo-timestamp',
            'X-Wc-Webhook-Timestamp',
            'x-wc-webhook-timestamp',
            'X-WC-Webhook-Timestamp',
            'X-Stripe-Signature-Timestamp',
            'x-stripe-signature-timestamp',
        ];

        foreach ($headerCandidates as $candidate) {
            if (!isset($headers[$candidate])) {
                continue;
            }

            $value = $headers[$candidate];
            if (is_array($value)) {
                $value = reset($value);
            }

            $timestamp = is_numeric($value) ? (int) $value : strtotime((string) $value);
            if ($timestamp && $timestamp > 0) {
                return $timestamp;
            }
        }

        $payloadCandidates = ['timestamp', 'created_at', 'sent_at'];
        foreach ($payloadCandidates as $candidate) {
            if (!isset($payload[$candidate])) {
                continue;
            }

            $value = $payload[$candidate];
            $timestamp = is_numeric($value) ? (int) $value : strtotime((string) $value);
            if ($timestamp && $timestamp > 0) {
                return $timestamp;
            }
        }

        return null;
    }
}
