<?php

namespace App\Http\Controllers;

use App\Models\ConfiguracionEmpresa;
use App\Support\TenantContext;
use App\Services\WompiCheckoutService;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
use Illuminate\View\View;

class WompiIntegracionController extends Controller
{
    private const SENSITIVE_KEYS = [
        'wompi_public_key',
        'wompi_integrity_secret',
        'wompi_events_secret',
    ];

    public function __construct(
        private readonly TenantContext $tenantContext,
        private readonly WompiCheckoutService $checkoutService,
    ) {}

    public function index(): View
    {
        $empresaId = $this->tenantContext->empresaId();
        abort_if($empresaId === null, 403);

        $settings = $this->loadSettings($empresaId);
        $configured = [
            'public_key' => trim((string) ($settings['wompi_public_key'] ?? '')) !== '',
            'integrity_secret' => trim((string) ($settings['wompi_integrity_secret'] ?? '')) !== '',
            'events_secret' => trim((string) ($settings['wompi_events_secret'] ?? '')) !== '',
            'redirect_url' => trim((string) ($settings['wompi_redirect_url'] ?? '')) !== '',
        ];

        return view('modules.configuracion.integraciones.wompi', [
            'settings' => $settings,
            'configured' => $configured,
            'generatedLink' => (string) session('wompi_checkout_url', ''),
            'generatedReference' => (string) session('wompi_checkout_reference', ''),
            'webhookUrl' => url('/webhooks/wompi'),
            'defaultRedirectUrl' => url('/dashboard'),
        ]);
    }

    public function update(Request $request): RedirectResponse
    {
        $empresaId = $this->tenantContext->empresaId();
        abort_if($empresaId === null, 403);

        $validated = $request->validate([
            'wompi_public_key' => ['nullable', 'string', 'max:255'],
            'wompi_integrity_secret' => ['nullable', 'string', 'max:255'],
            'wompi_events_secret' => ['nullable', 'string', 'max:255'],
            'wompi_redirect_url' => ['nullable', 'url', 'max:255'],
        ]);

        $existing = $this->loadSettings($empresaId);
        $toSave = [];

        foreach (self::SENSITIVE_KEYS as $key) {
            $incoming = trim((string) ($validated[$key] ?? ''));
            $current = trim((string) ($existing[$key] ?? ''));
            $value = $incoming !== '' ? $incoming : $current;
            $toSave[$key] = $value !== '' ? $this->encryptSettingValue($value) : '';
        }

        $toSave['wompi_redirect_url'] = trim((string) ($validated['wompi_redirect_url'] ?? $existing['wompi_redirect_url'] ?? ''));

        $this->upsertSettings($empresaId, $toSave);

        return back()->with('status', 'Integración Wompi actualizada.');
    }

    public function generateLink(Request $request): RedirectResponse
    {
        $empresaId = $this->tenantContext->empresaId();
        abort_if($empresaId === null, 403);

        $validated = $request->validate([
            'monto' => ['required', 'numeric', 'min:1000'],
            'descripcion' => ['required', 'string', 'max:180'],
            'referencia' => ['nullable', 'string', 'max:120'],
            'cliente_nombre' => ['nullable', 'string', 'max:120'],
            'cliente_email' => ['nullable', 'email', 'max:150'],
            'cliente_telefono' => ['nullable', 'string', 'max:40'],
        ]);

        $settings = $this->loadSettings($empresaId);
        $publicKey = trim((string) ($settings['wompi_public_key'] ?? ''));
        $integritySecret = trim((string) ($settings['wompi_integrity_secret'] ?? ''));

        if ($publicKey === '' || $integritySecret === '') {
            return back()
                ->withInput()
                ->with('error', 'Primero configura la llave pública y el secreto de integridad de Wompi.');
        }

        $reference = trim((string) ($validated['referencia'] ?? ''));
        if ($reference === '') {
            $reference = 'VXW-'.strtoupper(Str::random(10));
        }

        $checkoutUrl = $this->checkoutService->checkoutUrl(
            [
                'public_key' => $publicKey,
                'integrity_secret' => $integritySecret,
                'redirect_url' => trim((string) ($settings['wompi_redirect_url'] ?? url('/dashboard'))),
            ],
            [
                'amount_in_cents' => (int) round(((float) $validated['monto']) * 100),
                'currency' => 'COP',
                'reference' => $reference,
                'description' => trim((string) $validated['descripcion']),
                'customer_email' => trim((string) ($validated['cliente_email'] ?? '')),
                'customer_full_name' => trim((string) ($validated['cliente_nombre'] ?? '')),
                'customer_phone' => trim((string) ($validated['cliente_telefono'] ?? '')),
            ]
        );

        return back()
            ->withInput()
            ->with('status', 'Link de pago generado correctamente.')
            ->with('wompi_checkout_url', $checkoutUrl)
            ->with('wompi_checkout_reference', $reference);
    }

    /**
     * @return array<string, string>
     */
    private function loadSettings(int $empresaId): array
    {
        $keys = [
            'wompi_public_key',
            'wompi_integrity_secret',
            'wompi_events_secret',
            'wompi_redirect_url',
        ];

        $rows = ConfiguracionEmpresa::query()
            ->where('empresa_id', $empresaId)
            ->whereIn('clave', $keys)
            ->get(['clave', 'valor']);

        $settings = array_fill_keys($keys, '');
        foreach ($rows as $row) {
            $settings[(string) $row->clave] = (string) ($row->valor ?? '');
        }

        foreach (self::SENSITIVE_KEYS as $key) {
            $settings[$key] = $this->decryptSettingValue((string) ($settings[$key] ?? ''));
        }

        return $settings;
    }

    /**
     * @param  array<string, string>  $settings
     */
    private function upsertSettings(int $empresaId, array $settings): void
    {
        foreach ($settings as $key => $value) {
            ConfiguracionEmpresa::query()->updateOrCreate(
                ['empresa_id' => $empresaId, 'clave' => $key],
                ['valor' => $value]
            );
        }
    }

    private function encryptSettingValue(string $value): string
    {
        try {
            return Crypt::encryptString($value);
        } catch (\Throwable) {
            return $value;
        }
    }

    private function decryptSettingValue(string $value): string
    {
        if (trim($value) === '') {
            return '';
        }

        try {
            return (string) Crypt::decryptString($value);
        } catch (DecryptException) {
            return $value;
        } catch (\Throwable) {
            return $value;
        }
    }
}
