<?php

namespace App\Http\Controllers\Api\Hacienda;

use App\Http\Controllers\ApiController;
use App\Services\HaciendaWebhookService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Symfony\Component\HttpFoundation\Response;

class WebhookHaciendaController extends ApiController
{
    public function __construct() {}

    public function __invoke(Request $request): JsonResponse
    {
        $secret = trim((string) env('MH_WEBHOOK_SECRET', ''));

        Log::info('Incoming POST WEBHOOK MH Request', [
            'method' => $request->method(),
            'path' => $request->path(),
            'ip' => $request->ip(),
            'has_token' => trim((string) $request->query('token', '')) !== '',
        ]);

        if ($secret === '') {

            Log::error('MH webhook secret no configurado.');

            return response()->json([
                'success' => false,
                'message' => 'Webhook secret not configured.',
                'data' => [],
            ], Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        $token = trim((string) $request->query('token', ''));

        if (!hash_equals($secret, $token)) {

            Log::warning('MH webhook rechazado por token inválido.', [
                'path' => $request->path(),
                'ip' => $request->ip(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Invalid webhook token.',
                'data' => [],
            ], Response::HTTP_UNAUTHORIZED);
        }

        $rawBody = (string) $request->getContent();

        if ($rawBody === '') {
            return response()->json([
                'success' => false,
                'message' => 'Empty payload.',
                'data' => [],
            ], Response::HTTP_BAD_REQUEST);
        }

        $payload = json_decode($rawBody, true);

        if (!is_array($payload)) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid JSON payload.',
                'data' => [],
            ], Response::HTTP_BAD_REQUEST);
        }

        $clave = $this->firstString($payload, ['clave', 'Clave']);
        $estado = strtolower($this->firstString($payload, [
            'ind-estado',
            'ind_estado',
            'estado',
            'EstadoMensaje',
            'estado_mensaje',
        ]));

        if ($clave === '' || $estado === '') {

            Log::warning('MH webhook recibido sin clave o estado.', [
                'keys' => array_keys($payload),
                'ip' => $request->ip(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Missing required payload fields.',
                'data' => [],
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }


        Log::info('MH webhook recibido para procesamiento.', [
            'clave' => $clave,
            'estado' => $estado,
        ]);

        $payloadHash = hash('sha256', $rawBody);
        $logId = 0;

        if (Schema::hasTable('webhook_hacienda_logs')) {
            $headers = json_encode($request->headers->all(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            $payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            $hasPayloadHash = Schema::hasColumn('webhook_hacienda_logs', 'payload_hash');

            $insert = [
                'clave' => $clave,
                'estado' => $estado,
                'payload' => $payloadJson,
                'headers' => $headers,
                'ip' => $request->ip(),
                'procesado' => 0,
                'error' => null,
                'creado_en' => now(),
            ];

            if ($hasPayloadHash) {
                $insert['payload_hash'] = $payloadHash;
            }

            try {
                DB::table('webhook_hacienda_logs')->insertOrIgnore($insert);
            } catch (\Throwable $e) {

            Log::error('Error procesando webhook MH.', [
                'clave' => $clave ?? null,
                'estado' => $estado ?? null,
                'error' => $e->getMessage(),
            ]);

                DB::table('webhook_hacienda_logs')->insert($insert);
            }

            $query = DB::table('webhook_hacienda_logs')->where('clave', $clave);

            if ($hasPayloadHash) {
                $query->where('payload_hash', $payloadHash);
            } else {
                $query->where('estado', $estado);
            }

            $log = $query->orderByDesc('id')->first();

            if ($log && (int) ($log->procesado ?? 0) === 1) {
                return response()->json([
                    'success' => true,
                    'message' => 'Webhook already processed.',
                    'data' => [],
                ], Response::HTTP_OK);
            }

            $logId = $log ? (int) $log->id : 0;
        }

        try {
            app(HaciendaWebhookService::class)->process($payload, $logId);

            return response()->json([
                'success' => true,
                'message' => 'Webhook processed.',
                'data' => [],
            ], Response::HTTP_OK);
        } catch (\Throwable $e) {

            Log::error('Error procesando webhook MH.', [
                'clave' => $clave ?? null,
                'estado' => $estado ?? null,
                'error' => $e->getMessage(),
            ]);

            if ($logId > 0 && Schema::hasTable('webhook_hacienda_logs')) {
                DB::table('webhook_hacienda_logs')
                    ->where('id', $logId)
                    ->update([
                        'procesado' => 0,
                        'error' => mb_substr($e->getMessage(), 0, 65000),
                    ]);
            }

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'data' => [],
            ], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    private function firstString(array $payload, array $keys): string
    {
        foreach ($keys as $key) {
            if (array_key_exists($key, $payload) && $payload[$key] !== null) {
                return trim((string) $payload[$key]);
            }
        }

        return '';
    }
}
