<?php

namespace App\Services\Stripe;

use App\Models\Payment;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class PaymentGatewayContext
{
    /**
     * Resolve Stripe account id from payment gateway config.
     *
     * Source of truth is nested key: payment_gateway_configuration.stripe.stripe_account_id.
     * Legacy top-level key is supported as fallback to keep old rows working.
     *
     * @param  array<string, mixed>  $paymentGatewayConfiguration
     */
    public function resolveStripeAccountIdFromConfiguration(array $paymentGatewayConfiguration): ?string
    {
        $nested = trim((string) data_get($paymentGatewayConfiguration, 'stripe.stripe_account_id', ''));
        $legacy = trim((string) ($paymentGatewayConfiguration['stripe_account_id'] ?? ''));

        if ($nested !== '' && $legacy !== '' && $nested !== $legacy) {
            Log::warning('PaymentGatewayContext: stripe account mismatch in configuration payload', [
                'nested_account' => $nested,
                'legacy_account' => $legacy,
            ]);
        }

        if ($nested !== '') {
            return $nested;
        }

        if ($legacy !== '') {
            Log::warning('PaymentGatewayContext: using legacy top-level stripe_account_id fallback');

            return $legacy;
        }

        return null;
    }

    /**
     * Stripe account id for Connect.js / onboarding — does not require charges_enabled.
     *
     * @return array{user: ?User, stripe_account: ?string, methods: ?array}
     */
    public function resolveStripeConnectContext(string $franchiseeId, string $gateway = 'stripe'): array
    {
        $context = $this->resolveStripeContext($franchiseeId, $gateway, requireChargesEnabled: false);

        return $context;
    }

    /**
     * @return array{user: ?User, stripe_account: ?string, methods: ?array}
     */
    public function resolveStripeContext(
        string $franchiseeId,
        string $gateway = 'stripe',
        bool $requireChargesEnabled = true,
    ): array {
        $user = User::where('franchisee_id', $franchiseeId)->first();

        if (!$user || $user->role === 'super_admin') {
            return [
                'user' => $user,
                'stripe_account' => null,
                'methods' => null,
            ];
        }

        $setting = Setting::where('franchisee_id', $franchiseeId)
            ->whereRaw(
                "payment_gateway_configuration -> '{$gateway}' ->> 'status' = 'active'"
            )
            ->first();

        if (!$setting) {
            throw new \RuntimeException("Selected franchisee has no active {$gateway} payment method.");
        }

        $configuration = is_array($setting->payment_gateway_configuration)
            ? $setting->payment_gateway_configuration
            : [];
        $methods = $configuration[$gateway] ?? null;
        $accountId = $gateway === 'stripe'
            ? $this->resolveStripeAccountIdFromConfiguration($configuration)
            : ($methods['stripe_account_id'] ?? null);

        if ($accountId && $requireChargesEnabled) {
            app(StripeConnectService::class)->assertChargesEnabled($accountId);
        }

        return [
            'user' => $user,
            'stripe_account' => $accountId,
            'methods' => $methods,
        ];
    }

    public function assertNotAlreadyPaid(string $registrationId): void
    {
        $paid = Payment::where('registration_id', $registrationId)
            ->where('status', 'succeeded')
            ->exists();

        if ($paid) {
            throw new \RuntimeException('This registration has already been paid.');
        }
    }

    public function idempotencyKey(string $registrationId, string $purpose, int $amountCents): string
    {
        return hash('sha256', implode('|', [$registrationId, $purpose, (string) $amountCents]));
    }
}
