<?php
// app/Services/Payments/CheckoutSessionService.php

declare(strict_types=1);

namespace App\Services\Payments;

use App\Events\PaymentLinkSent;
use App\Mail\PaymentRequestMail;
use App\Models\Payment;
use Illuminate\Contracts\Routing\UrlGenerator;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Stripe\Checkout\Session as StripeCheckoutSession;
use Stripe\Exception\ApiErrorException;
use Stripe\StripeClient;

/**
 * Builds a Stripe Checkout Session for one-off charges and emails the customer.
 *
 * Responsibilities:
 *  - Create Checkout Session with consistent metadata
 *  - Persist session id in Payment.gateway_meta['checkout_session']
 *  - Email the customer a pay link (with optional attachments via your Mailable)
 *  - Emit PaymentLinkSent event
 */
class CheckoutSessionService
{
    public function __construct(
        private readonly StripeClient $stripe,
        private readonly UrlGenerator $url, // for route() generation
    ) {}

    /**
     * Create a one-off Checkout Session and email the link.
     *
     * @return array{session_id:string, url:string}
     */
    public function initCheckoutAndEmail(Payment $payment): array
    {
        $currency = strtolower($payment->currency ?? 'nzd');
        $description = mb_substr($payment->reason ?? 'Additional charge', 0, 500);

        // Metadata shared on both the session and the eventual PaymentIntent
        $metadata = [
            'payment_id' => (string) $payment->id,
            'job_id'     => (string) $payment->job_id,
            'kind'       => 'one_off',
        ];

        // Stable idempotency per Payment + amount/currency
        $idem = sprintf('chk:%d:%s', $payment->id, sha1($payment->amount_cents.'|'.$currency));

        try {
            /** @var StripeCheckoutSession $session */
            $session = $this->stripe->checkout->sessions->create([
                'mode'                 => 'payment',
                'payment_intent_data'  => ['metadata' => $metadata],
                'line_items'           => [[
                    'price_data' => [
                        'currency'     => $currency,
                        'product_data' => [
                            'name'        => 'One-off charge',
                            'description' => $description,
                        ],
                        'unit_amount'  => (int) $payment->amount_cents,
                    ],
                    'quantity' => 1,
                ]],
                'success_url'          => $this->url->route('payments.public.thanks', $payment->public_token),
                'cancel_url'           => $this->url->route('payments.public.cancel', $payment->public_token),
                'metadata'             => $metadata,
            ], ['idempotency_key' => $idem]);

            // Persist session id
            $meta = (array) ($payment->gateway_meta ?? []);
            $meta['checkout_session'] = $session->id;
            $payment->forceFill(['gateway_meta' => $meta])->save();

            // Email customer a pay link
            $customerEmail = optional($payment->job?->customer)->email;
            if ($customerEmail) {
                Mail::to($customerEmail)->send(new PaymentRequestMail($payment, $session->url));
            }

            // Notify the system
            event(new PaymentLinkSent($payment));

            return ['session_id' => $session->id, 'url' => $session->url];
        } catch (ApiErrorException $e) {
            Log::error('[Stripe] Checkout session error', [
                'payment_id' => $payment->id,
                'stripe_code'=> $e->getStripeCode(),
                'type'       => $e->getError()?->type,
                'message'    => $e->getMessage(),
            ]);

            abort(502, 'Could not create payment request. Please try again.');
        }
    }
}
