<?php

namespace App\Helpers;

use Stripe\Account;
use Stripe\AccountLink;
use Stripe\Exception\ApiErrorException;
use Stripe\Exception\SignatureVerificationException;
use Stripe\PaymentIntent;
use Stripe\SetupIntent;
use Stripe\Stripe;
use Stripe\StripeClient;
use Stripe\Webhook;

class StripeHelper
{
    public static function init(): void
    {
        Stripe::setApiKey(config('services.stripe.secret'));
    }

    /**
     * @deprecated Prefer App\Services\Stripe\PaymentIntentService::createPaymentIntent()
     *
     * @param  array<string, mixed>  $data
     */
    public static function createIntent(array $data)
    {
        return app(\App\Services\Stripe\PaymentIntentService::class)->createPaymentIntent($data);
    }

    /**
     * @deprecated Prefer App\Services\Stripe\PaymentIntentService::createSetupIntent()
     *
     * @param  array<string, mixed>  $data
     */
    public static function setupIntent(array $data)
    {
        return app(\App\Services\Stripe\PaymentIntentService::class)->createSetupIntent($data);
    }

    public static function updateIntent(array $data)
    {
        self::init();
        $stripe = new StripeClient(config('services.stripe.secret'));

        if (empty($data['payment_intent_id'])) {
            throw new \Exception('Payment Intent ID is required.');
        }

        if (empty($data['email'])) {
            throw new \Exception('Customer email is required.');
        }

        try {
            $stripeAccount = $data['stripe_account'] ?? null;
            $requestOptions = app(\App\Services\Stripe\StripeConnectService::class)
                ->connectRequestOptions($stripeAccount);

            $customers = $stripe->customers->search([
                'query' => "email:'{$data['email']}'",
            ], $requestOptions);

            $customerId = !empty($customers->data) ? $customers->data[0]->id : null;

            if (!$customerId) {
                $customer = $stripe->customers->create([
                    'email' => $data['email'],
                ], $requestOptions);
                $customerId = $customer->id;
            }

            return $stripe->paymentIntents->update(
                $data['payment_intent_id'],
                [
                    'customer' => $customerId,
                    'setup_future_usage' => 'off_session',
                ],
                $requestOptions
            );
        } catch (ApiErrorException $e) {
            throw new \Exception('Stripe API Error: '.$e->getMessage());
        } catch (\Throwable $e) {
            throw new \Exception('Unexpected Error: '.$e->getMessage());
        }
    }

    public static function retrieveIntent(string $paymentIntentId, ?string $stripeAccount = null)
    {
        self::init();

        $options = app(\App\Services\Stripe\StripeConnectService::class)
            ->connectRequestOptions($stripeAccount);

        return PaymentIntent::retrieve($paymentIntentId, [], $options);
    }

    public static function retrieveSetupIntent(string $setupIntentId, ?string $stripeAccount = null)
    {
        self::init();

        $options = app(\App\Services\Stripe\StripeConnectService::class)
            ->connectRequestOptions($stripeAccount);

        return SetupIntent::retrieve($setupIntentId, [], $options);
    }

    public static function stripeWebhook($payload, $sigHeader)
    {
        $secret = config('services.stripe.webhook_secret');

        try {
            return Webhook::constructEvent($payload, $sigHeader, $secret);
        } catch (\UnexpectedValueException $e) {
            throw new \Exception('Invalid payload: '.$e->getMessage());
        } catch (SignatureVerificationException $e) {
            throw new \Exception('Invalid signature: '.$e->getMessage());
        }
    }

    public static function retrieveConnectedAccount(string $accountId): Account
    {
        self::init();

        try {
            return Account::retrieve($accountId);
        } catch (ApiErrorException $e) {
            throw new \Exception('Failed to retrieve Stripe account: '.$e->getMessage());
        } catch (\Throwable $e) {
            throw new \Exception('An unexpected error occurred: '.$e->getMessage());
        }
    }

    public static function createConnectedAccount(string $email, string $country = 'US')
    {
        self::init();

        try {
            return Account::create([
                'type' => 'standard',
                'country' => $country,
                'email' => $email,
                'capabilities' => [
                    'card_payments' => ['requested' => true],
                    'transfers' => ['requested' => true],
                ],
            ]);
        } catch (ApiErrorException $e) {
            throw new \Exception('Failed to create Stripe account: '.$e->getMessage());
        } catch (\Throwable $e) {
            throw new \Exception('An unexpected error occurred:'.$e->getMessage());
        }
    }

    public static function createAccountLink($connectedAccountId)
    {
        try {
            self::init();

            $accountLink = AccountLink::create([
                'account' => $connectedAccountId,
                'refresh_url' => config('services.stripe.refresh_url'),
                'return_url' => config('services.stripe.return_url'),
                'type' => 'account_onboarding',
            ]);

            return $accountLink->url;
        } catch (ApiErrorException $e) {
            throw new \Exception('Stripe onboarding link creation failed: '.$e->getMessage());
        } catch (\Throwable $e) {
            throw new \Exception('An unexpected error occurred:'.$e->getMessage());
        }
    }

    public static function chargeSavedCardAutopay(array $data)
    {
        self::init();

        try {
            if (
                empty($data['amount']) ||
                empty($data['currency']) ||
                empty($data['customer_id']) ||
                empty($data['payment_method_id'])
            ) {
                throw new \Exception('Missing required autopay parameters.');
            }

            $intentData = [
                'amount' => (int) $data['amount'],
                'currency' => $data['currency'],
                'customer' => $data['customer_id'],
                'payment_method' => $data['payment_method_id'],
                'off_session' => true,
                'confirm' => true,
                'automatic_payment_methods' => [
                    'enabled' => true,
                    'allow_redirects' => 'never',
                ],
                'metadata' => array_filter([
                    'franchisee_id' => $data['franchisee_id'] ?? null,
                    'registration_id' => $data['registration_id'] ?? null,
                    'source' => 'autopay',
                ]),
            ];

            $options = [];
            if (!empty($data['idempotency_key'])) {
                $options['idempotency_key'] = $data['idempotency_key'];
            }

            if (!empty($data['stripe_account'])) {
                app(\App\Services\Stripe\StripeConnectService::class)->assertChargesEnabled($data['stripe_account']);
                $options['stripe_account'] = $data['stripe_account'];
                $intentData['metadata']['stripe_account_id'] = $data['stripe_account'];
            }

            return PaymentIntent::create($intentData, $options);
        } catch (\Stripe\Exception\CardException $e) {
            return [
                'success' => false,
                'status' => 'failed',
                'type' => 'card_error',
                'message' => $e->getError()->message,
                'code' => $e->getError()->code,
            ];
        } catch (ApiErrorException $e) {
            throw new \Exception('Stripe API error during autopay: '.$e->getMessage());
        } catch (\Throwable $e) {
            throw new \Exception('Unexpected autopay error: '.$e->getMessage());
        }
    }
}
