<?php

namespace portalpeople\stripe\models;

use portalpeople\stripe\components\StripeClient;
use portalpeople\stripe\Module;
use RuntimeException;
use Yii;

class HostedPage
{
    /**
     * Create a Stripe Payment Link for a hosted checkout page.
     *
     * @param array $params Line items and payment configuration
     *   - items: [{name, price_data: {currency, unit_amount, product_data: {name}}}]
     *   - successUrl: URL redirect on success
     *   - cancelUrl: URL redirect on cancel
     *   - mode: 'payment' (default) or 'subscription'
     *   - customerEmail: optional customer email
     *   - metadata: optional key-value pairs
     * @return array Checkout session containing 'url' and session details
     * @throws RuntimeException
     */
    public static function createCheckoutSession(array $params): array
    {
        /** @var Module $module */
        $module = Yii::$app->getModule('stripe');
        if (!$module) {
            throw new RuntimeException('Stripe module not configured.');
        }

        try {
            $client = StripeClient::fromModule($module);
        } catch (RuntimeException $e) {
            throw new RuntimeException('Failed to initialize Stripe client: ' . $e->getMessage());
        }

        // Validate required parameters
        if (empty($params['items'])) {
            throw new RuntimeException('Parameter "items" is required.');
        }
        if (empty($params['successUrl'])) {
            throw new RuntimeException('Parameter "successUrl" is required.');
        }
        if (empty($params['cancelUrl'])) {
            throw new RuntimeException('Parameter "cancelUrl" is required.');
        }

        $payload = [
            'line_items' => $params['items'],
            'mode' => $params['mode'] ?? 'payment',
            'success_url' => $params['successUrl'],
            'cancel_url' => $params['cancelUrl'],
        ];

        if (!empty($params['customerEmail'])) {
            $payload['customer_email'] = $params['customerEmail'];
        }

        if (!empty($params['metadata'])) {
            $payload['metadata'] = $params['metadata'];
        }

        if (!empty($params['allowPromotionCodes'])) {
            $payload['allow_promotion_codes'] = true;
        }

        return $this->executeCheckoutSessionCreate($client, $payload);
    }

    /**
     * Create a Payment Link (reusable, shareable checkout page).
     *
     * @param array $params Payment link configuration
     *   - items: [{price, quantity}] or [{price_data}]
     *   - metadata: optional
     *   - customText: optional instructions shown on page
     * @return array Payment link with 'url' and link details
     * @throws RuntimeException
     */
    public static function createPaymentLink(array $params): array
    {
        /** @var Module $module */
        $module = Yii::$app->getModule('stripe');
        if (!$module) {
            throw new RuntimeException('Stripe module not configured.');
        }

        try {
            $client = StripeClient::fromModule($module);
        } catch (RuntimeException $e) {
            throw new RuntimeException('Failed to initialize Stripe client: ' . $e->getMessage());
        }

        if (empty($params['items'])) {
            throw new RuntimeException('Parameter "items" is required.');
        }

        $payload = [
            'line_items' => $params['items'],
            'after_completion' => [
                'type' => 'redirect',
                'redirect' => ['url' => $params['redirectUrl'] ?? Yii::$app->homeUrl],
            ],
        ];

        if (!empty($params['metadata'])) {
            $payload['metadata'] = $params['metadata'];
        }

        if (!empty($params['customText'])) {
            $payload['custom_text'] = $params['customText'];
        }

        return $this->executePaymentLinkCreate($client, $payload);
    }

    /**
     * Retrieve a checkout session or payment link.
     *
     * @param string $sessionId Checkout session or payment link ID
     * @param string $type 'checkout_session' or 'payment_link'
     * @return array Session/link details
     * @throws RuntimeException
     */
    public static function retrieve(string $sessionId, string $type = 'checkout_session'): array
    {
        /** @var Module $module */
        $module = Yii::$app->getModule('stripe');
        if (!$module) {
            throw new RuntimeException('Stripe module not configured.');
        }

        try {
            $client = StripeClient::fromModule($module);
        } catch (RuntimeException $e) {
            throw new RuntimeException('Failed to initialize Stripe client: ' . $e->getMessage());
        }

        if ($type === 'payment_link') {
            return $client->makeRequest('GET', "/payment_links/{$sessionId}");
        }

        return $client->makeRequest('GET', "/checkout/sessions/{$sessionId}");
    }

    /**
     * Create a Stripe Checkout Session from a Carts model instance.
     *
     * @param Carts  $cart       A loaded Carts model
     * @param array  $params     Must include 'successUrl' and 'cancelUrl'; optionally 'metadata'
     * @return array Checkout session containing 'url' and session details
     * @throws RuntimeException
     */
    public static function createCheckoutSessionFromCart(Carts $cart, array $params): array
    {
        /** @var Module $module */
        $module = Yii::$app->getModule('stripe');
        if (!$module) {
            throw new RuntimeException('Stripe module not configured.');
        }

        try {
            $client = StripeClient::fromModule($module);
        } catch (RuntimeException $e) {
            throw new RuntimeException('Failed to initialize Stripe client: ' . $e->getMessage());
        }

        if (empty($params['successUrl'])) {
            throw new RuntimeException('Parameter "successUrl" is required.');
        }
        if (empty($params['cancelUrl'])) {
            throw new RuntimeException('Parameter "cancelUrl" is required.');
        }

        $lineItems = static::buildLineItemsFromCart($cart);

        if (empty($lineItems)) {
            throw new RuntimeException('Cart contains no payable lines.');
        }

        $payload = [
            'line_items' => $lineItems,
            'mode' => $params['mode'] ?? 'payment',
            'success_url' => $params['successUrl'],
            'cancel_url' => $params['cancelUrl'],
        ];

        if (!empty($cart->email)) {
            $payload['customer_email'] = $cart->email;
        }

        $metadata = $params['metadata'] ?? [];
        if (!empty($cart->id)) {
            $metadata['cart_id'] = $cart->id;
        }
        if (!empty($cart->orderref)) {
            $metadata['order_ref'] = $cart->orderref;
        }
        if (!empty($metadata)) {
            $payload['metadata'] = $metadata;
        }

        return static::executeCheckoutSessionCreate($client, $payload);
    }

    /**
     * Map active, non-delivery cart lines to Stripe line_items format.
     *
     * @param Carts $cart
     * @return array
     */
    private static function buildLineItemsFromCart(Carts $cart): array
    {
        $lineItems = [];

        foreach ($cart->cartlines as $line) {
            $unitPrice = (float) $line->price;
            $qty = (int) $line->qty;

            if ($unitPrice <= 0 || $qty <= 0) {
                continue;
            }

            $currency = strtolower((string) ($line->currency_code ?: 'gbp'));

            $lineItems[] = [
                'price_data' => [
                    'currency' => $currency,
                    'unit_amount' => (int) round($unitPrice * 100),
                    'product_data' => [
                        'name' => (string) $line->product_name,
                    ],
                ],
                'quantity' => $qty,
            ];
        }

        return $lineItems;
    }

    private static function executeCheckoutSessionCreate(StripeClient $client, array $payload): array
    {
        return $client->makeRequest('POST', '/checkout/sessions', $payload);
    }

    private static function executePaymentLinkCreate(StripeClient $client, array $payload): array
    {
        return $client->makeRequest('POST', '/payment_links', $payload);
    }
}
