<?php

namespace GriffinForms\Admin\Html\Elements\Submission;

use GriffinForms\Includes\Helpers\Currency;
use GriffinForms\Includes\Integrations\Providers;

class Payment extends \GriffinForms\Admin\Html\Elements\Submission\Format
{
    protected $field;
    protected $field_value;
    protected $submission_id;
    protected $payment_status;
    protected $payment_meta = [];
    protected $cart = [];
    protected $form_id = 0;

    public function __construct($field, $field_value = [], $context = [])
    {
        $this->field = $field;
        $this->field_value = $this->normalizeFieldValue($field_value);
        $this->submission_id = isset($context['submission_id']) ? absint($context['submission_id']) : 0;
        $this->payment_status = isset($context['payment_status']) ? sanitize_text_field($context['payment_status']) : '';
        $this->payment_meta = isset($context['payment_meta']) ? $this->normalizeMeta($context['payment_meta']) : [];
        $this->cart = isset($context['cart']) && is_array($context['cart']) ? $context['cart'] : [];
        $this->form_id = isset($context['form_id']) ? absint($context['form_id']) : 0;
    }

    protected function normalizeFieldValue($field_value)
    {
        if (is_string($field_value) && $field_value !== '') {
            $decoded = json_decode($field_value, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                return $this->normalizeFieldValue($decoded);
            }
            $maybe = maybe_unserialize($field_value);
            if (is_array($maybe)) {
                return $this->normalizeFieldValue($maybe);
            }
            return $field_value;
        }

        if (!is_array($field_value)) {
            return $field_value;
        }

        if (
            array_keys($field_value) === range(0, count($field_value) - 1)
            && count($field_value) === 1
            && isset($field_value[0])
            && !$this->looksLikePaymentItemsList($field_value)
        ) {
            return $this->normalizeFieldValue($field_value[0]);
        }

        foreach ($field_value as $key => $entry) {
            if (is_string($entry) || is_array($entry)) {
                $field_value[$key] = $this->normalizeFieldValue($entry);
            }
        }

        return $field_value;
    }

    public function getHtml()
    {
        $items = $this->resolveItems();
        $gateway = $this->resolveGateway($items);

        echo '<div class="griffinforms-payment-admin-block">';
        $this->renderGatewayHeader($gateway);

        if (!empty($items)) {
            echo '<div class="griffinforms-payment-admin-items">';
            foreach ($items as $item) {
                $qty_text = $item['quantity'] > 1 ? ' × ' . (int) $item['quantity'] : '';
                $description = $item['description'] ?? ($item['product_description'] ?? '');
                $image = $item['image'] ?? ($item['product_image'] ?? '');
                echo '<div class="d-flex gap-3 align-items-start mb-2">';
                if (!empty($image)) {
                    echo '<div class="griffinforms-payment-admin-thumb rounded overflow-hidden" style="width:48px;height:48px;">';
                    echo '<img src="' . esc_url($image) . '" alt="' . esc_attr($item['label']) . '" style="width:48px;height:48px;object-fit:contain;">';
                    echo '</div>';
                }
                echo '<div class="flex-grow-1">';
                echo '<div class="fw-semibold">' . esc_html($item['label']) . $qty_text . '</div>';
                if (!empty($description)) {
                    echo '<div class="text-muted small">' . esc_html($description) . '</div>';
                }
                echo '</div>';
                echo '</div>';
            }
            echo '</div>';
        }

        $this->renderPaymentMeta();
        $this->renderResumeButton();
        echo '</div>';
    }

    protected function resolveItems(): array
    {
        $items = [];
        $currency_helper = Currency::getInstance();
        $currency = $this->cart['currency'] ?? 'USD';
        $product_map = $this->buildProductMap();
        $target_field_id = (int) $this->field->getProp('id');
        $cart_items = !empty($this->cart['items']) && is_array($this->cart['items']) ? $this->cart['items'] : [];
        $matched_cart_items = [];

        if (!empty($cart_items)) {
            foreach ($cart_items as $entry) {
                if (!is_array($entry)) {
                    continue;
                }

                if ((int) ($entry['field_id'] ?? 0) !== $target_field_id) {
                    continue;
                }

                $matched_cart_items[] = $entry;
            }

            // If the cart has items but none are tagged to this field, fall back only when the
            // form effectively has a single payment field worth of items in the summary context.
            if (empty($matched_cart_items) && count($cart_items) > 0 && $this->countPaymentFieldsInCart($cart_items) <= 1) {
                $matched_cart_items = $cart_items;
            }

            foreach ($matched_cart_items as $entry) {
                $product_id = $entry['product_id'] ?? '';
                $label = $entry['label'] ?? '';
                $product_meta = $this->findProductMeta($product_id, $label, $product_map);
                $image = $entry['image']
                    ?? ($product_meta['image'] ?? ($product_meta['product_image'] ?? ''));
                $description = $product_meta['description'] ?? ($product_meta['product_description'] ?? '');

                $items[] = array(
                    'label'    => $entry['label'] ?? $entry['product_id'] ?? __('Product', 'griffinforms-form-builder'),
                    'quantity' => (int) ($entry['quantity'] ?? 1),
                    'unit_price' => (float) ($entry['unit_price'] ?? 0),
                    'subtotal'   => (float) ($entry['subtotal'] ?? 0),
                    'currency'   => $this->resolveCurrencyCode($entry['currency'] ?? $currency, $currency),
                    'image'      => $image,
                    'description' => $description,
                );
            }
        }

        $field_entries = is_array($this->field_value) ? $this->extractFieldEntries($this->field_value) : [];
        if (empty($items) && !empty($field_entries)) {
            foreach ($field_entries as $entry) {
                $product_id = $entry['product_id'] ?? '';
                $label = $entry['product_name'] ?? $entry['product_id'] ?? __('Product', 'griffinforms-form-builder');
                $product_meta = $this->findProductMeta($product_id, $label, $product_map);
                $image = $entry['image']
                    ?? ($entry['product_image'] ?? ($product_meta['image'] ?? ($product_meta['product_image'] ?? '')));
                $description = $entry['description']
                    ?? ($entry['product_description'] ?? ($product_meta['description'] ?? ($product_meta['product_description'] ?? '')));
                $items[] = array(
                    'label'    => $label,
                    'quantity' => (int) ($entry['quantity'] ?? 1),
                    'unit_price' => (float) ($entry['unit_price'] ?? 0),
                    'subtotal'   => (float) ($entry['total'] ?? 0),
                    'currency'   => $this->resolveCurrencyCode($entry['currency'] ?? $currency, $currency),
                    'image'      => $image,
                    'description' => $description,
                );
            }
        }

        if (empty($items) && is_array($this->field_value) && $this->looksLikeScalarSelectionList($this->field_value)) {
            foreach ($this->field_value as $entry) {
                if (!is_string($entry)) {
                    continue;
                }

                $label = trim($entry);
                if ($label === '' || $this->looksLikeGatewayValue($label)) {
                    continue;
                }

                $items[] = array(
                    'label'       => $label,
                    'quantity'    => 1,
                    'unit_price'  => 0.0,
                    'subtotal'    => 0.0,
                    'currency'    => $this->resolveCurrencyCode($currency, $currency),
                    'image'       => '',
                    'description' => '',
                );
            }
        }

        if (empty($items) && is_string($this->field_value)) {
            $label = trim($this->field_value);
            if ($label !== '' && !$this->looksLikeGatewayValue($label)) {
                $items[] = array(
                    'label'       => $label,
                    'quantity'    => 1,
                    'unit_price'  => 0.0,
                    'subtotal'    => 0.0,
                    'currency'    => $this->resolveCurrencyCode($currency, $currency),
                    'image'       => '',
                    'description' => '',
                );
            }
        }

        return $items;
    }

    protected function looksLikeScalarSelectionList(array $value): bool
    {
        if ($value === [] || array_keys($value) !== range(0, count($value) - 1)) {
            return false;
        }

        foreach ($value as $entry) {
            if (!is_string($entry)) {
                return false;
            }
        }

        return true;
    }

    protected function looksLikeGatewayValue(string $value): bool
    {
        $normalized = strtolower(trim($value));
        if ($normalized === '') {
            return false;
        }

        return in_array($normalized, ['stripe', 'paypal', 'razorpay', 'square', 'authorize.net'], true);
    }

    protected function countPaymentFieldsInCart(array $cart_items): int
    {
        $field_ids = [];

        foreach ($cart_items as $entry) {
            if (!is_array($entry)) {
                continue;
            }

            $field_id = (int) ($entry['field_id'] ?? 0);
            if ($field_id > 0) {
                $field_ids[$field_id] = true;
            }
        }

        return count($field_ids);
    }

    protected function extractFieldEntries(array $field_value): array
    {
        if (isset($field_value['items']) && is_array($field_value['items'])) {
            return $field_value['items'];
        }

        if ($this->looksLikePaymentItemsList($field_value)) {
            return $field_value;
        }

        foreach ($field_value as $entry) {
            if (!is_array($entry)) {
                continue;
            }

            $nested = $this->extractFieldEntries($entry);
            if (!empty($nested)) {
                return $nested;
            }
        }

        return [];
    }

    protected function looksLikePaymentItemsList(array $value): bool
    {
        if ($value === [] || array_keys($value) !== range(0, count($value) - 1)) {
            return false;
        }

        $sample = current($value);
        if (!is_array($sample)) {
            return false;
        }

        return isset($sample['product_id']) || isset($sample['product_name']) || isset($sample['total']);
    }

    /**
     * Build a map of product_id => product data from multiple sources.
     */
    protected function buildProductMap(): array
    {
        $map = [];

        if (is_array($this->field_value) && isset($this->field_value['items']) && is_array($this->field_value['items'])) {
            $this->addProductsToMap($map, $this->field_value['items']);
        }

        $field_settings = $this->normalizeMaybeEncodedArray($this->field->getProp('field_settings'));
        if (is_array($field_settings) && isset($field_settings['products'])) {
            $this->addProductsToMap($map, $field_settings['products']);
        }

        $field_options = $this->normalizeMaybeEncodedArray($this->field->getProp('field_options'));
        if (is_array($field_options)) {
            if (isset($field_options['products'])) {
                $this->addProductsToMap($map, $field_options['products']);
            } elseif ($this->looksLikeProductsList($field_options)) {
                $this->addProductsToMap($map, $field_options);
            }
        }

        return $map;
    }

    protected function normalizeMaybeEncodedArray($value)
    {
        if (is_array($value)) {
            return $value;
        }

        if (!is_string($value) || $value === '') {
            return $value;
        }

        $decoded = maybe_unserialize($value);
        if (is_array($decoded)) {
            return $decoded;
        }

        if (is_string($decoded) && $decoded !== $value) {
            $json = json_decode($decoded, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($json)) {
                return $json;
            }
        }

        $json = json_decode($value, true);
        if (json_last_error() === JSON_ERROR_NONE && is_array($json)) {
            return $json;
        }

        return $value;
    }

    /**
     * Helper to add product entries into map.
     *
     * @param array $map Reference to map.
     * @param array $products List of product arrays.
     */
    protected function addProductsToMap(array &$map, $products): void
    {
        if (!is_array($products)) {
            return;
        }

        foreach ($products as $product_entry) {
            if (!is_array($product_entry)) {
                continue;
            }
            $pid = isset($product_entry['id']) ? sanitize_text_field($product_entry['id']) : '';
            $pid_alt = isset($product_entry['product_id']) ? sanitize_text_field($product_entry['product_id']) : '';
            $pid = $pid !== '' ? $pid : $pid_alt;
            $name = isset($product_entry['name']) ? sanitize_text_field($product_entry['name']) : (isset($product_entry['product_name']) ? sanitize_text_field($product_entry['product_name']) : '');

            if ($pid !== '') {
                $map[$pid] = $product_entry;
            }
            if ($name !== '') {
                $map['__name__' . strtolower($name)] = $product_entry;
            }
        }
    }

    /**
     * Detect if an array resembles a products list.
     */
    protected function looksLikeProductsList($data): bool
    {
        if (!is_array($data) || empty($data)) {
            return false;
        }
        // keyed by numeric indices or associative with id/product_id
        $sample = current($data);
        if (!is_array($sample)) {
            return false;
        }
        return isset($sample['id']) || isset($sample['product_id']) || isset($sample['product_name']) || isset($sample['name']);
    }

    /**
     * Try to find product metadata by id or name.
     */
    protected function findProductMeta($product_id, $label, array $product_map): array
    {
        $product_id = is_string($product_id) ? $product_id : (string) $product_id;
        if ($product_id !== '' && isset($product_map[$product_id])) {
            return $product_map[$product_id];
        }

        $label_key = is_string($label) ? strtolower(trim($label)) : '';
        if ($label_key !== '') {
            $by_name_key = '__name__' . $label_key;
            if (isset($product_map[$by_name_key])) {
                return $product_map[$by_name_key];
            }
        }

        return array();
    }

    protected function resolveTotals(array $items): array
    {
        $currency = $this->cart['currency'] ?? 'USD';
        $subtotal = 0.0;
        if (!empty($items)) {
            $currency = $items[0]['currency'] ?: $currency;
            foreach ($items as $item) {
                $subtotal += (float) $item['subtotal'];
            }
        }

        $tax_total = 0.0;
        foreach ($this->resolveTaxLines() as $tax) {
            $tax_total += (float) $tax['amount'];
        }

        return array(
            'currency' => $currency,
            'subtotal' => $subtotal,
            'tax_total' => $tax_total,
            'total' => $subtotal + $tax_total,
        );
    }

    protected function resolveTaxLines(): array
    {
        $tax_lines = [];
        if (!empty($this->cart['tax_lines'])) {
            foreach ($this->cart['tax_lines'] as $line) {
                if ((int) ($line['field_id'] ?? 0) !== (int) $this->field->getProp('id')) {
                    continue;
                }
                $tax_lines[] = $line;
            }
        }
        return $tax_lines;
    }

    protected function resolveGateway(array $items): string
    {
        if (!empty($this->field_value['gateway'])) {
            return sanitize_text_field($this->field_value['gateway']);
        }
        if (!empty($this->payment_meta['paypal']['gateway'])) {
            return sanitize_text_field($this->payment_meta['paypal']['gateway']);
        }
        if (!empty($this->payment_meta['stripe']['gateway'])) {
            return sanitize_text_field($this->payment_meta['stripe']['gateway']);
        }
        return '';
    }

    protected function renderGatewayHeader(string $gateway): void
    {
        if ($gateway === '') {
            return;
        }

        $provider = Providers::getInstance()->get($gateway, false);
        $label = $provider['name'] ?? ucfirst(str_replace(['_', '-'], ' ', $gateway));
        $icon = $provider['icon'] ?? '';

        echo '<div class="griffinforms-payment-admin-gateway d-flex align-items-center gap-2 mb-3">';
        if ($icon !== '') {
            echo '<img src="' . esc_url($icon) . '" alt="' . esc_attr($label) . '" style="width:24px;height:24px;object-fit:contain;" loading="lazy">';
        }
        echo '<span class="fw-semibold">' . esc_html($label) . '</span>';
        echo '</div>';
    }

    protected function renderPaymentMeta(): void
    {
        if (empty($this->payment_meta)) {
            return;
        }

        $stripe_meta = is_array($this->payment_meta['stripe'] ?? null) ? $this->payment_meta['stripe'] : [];
        $paypal_meta = is_array($this->payment_meta['paypal'] ?? null) ? $this->payment_meta['paypal'] : [];
        $intent_id = $stripe_meta['intent_id'] ?? '';
        $client_secret = $stripe_meta['client_secret'] ?? '';
        $order_id = $paypal_meta['order_id'] ?? '';
        $capture_id = $paypal_meta['capture_id'] ?? '';

        if (!$intent_id && !$client_secret && !$order_id && !$capture_id) {
            return;
        }

        echo '<div class="griffinforms-payment-admin-meta small text-muted mt-3">';
        if ($intent_id) {
            echo '<div>' . esc_html__('Intent ID:', 'griffinforms-form-builder') . ' ' . esc_html($intent_id) . '</div>';
        }
        if ($client_secret) {
            echo '<div>' . esc_html__('Client secret stored.', 'griffinforms-form-builder') . '</div>';
        }
        if ($order_id) {
            echo '<div>' . esc_html__('Order ID:', 'griffinforms-form-builder') . ' ' . esc_html($order_id) . '</div>';
        }
        if ($capture_id) {
            echo '<div>' . esc_html__('Capture ID:', 'griffinforms-form-builder') . ' ' . esc_html($capture_id) . '</div>';
        }
        echo '</div>';
    }

    protected function renderResumeButton(): void
    {
        if ($this->payment_status !== 'pending') {
            return;
        }
        $retry = $this->payment_meta['retry'] ?? [];
        $token = isset($retry['token']) ? sanitize_text_field($retry['token']) : '';
        if ($token === '' || $this->submission_id <= 0) {
            return;
        }
        $resume_url = '';
        if (!empty($this->payment_meta['retry']['resume_url'])) {
            $resume_url = esc_url_raw($this->payment_meta['retry']['resume_url']);
        }
        if ($resume_url === '') {
            $resume_url = home_url('/form-page/');
        }
        $resume_url = add_query_arg(
            array(
                'gf_payment_resume' => $this->submission_id . ':' . $token,
            ),
            $resume_url
        );
        echo '<div class="mt-3">';
        echo '<a class="btn btn-sm btn-primary" href="' . esc_url($resume_url) . '" target="_blank" rel="noopener">';
        echo esc_html__('Resume payment', 'griffinforms-form-builder');
        echo '</a>';
        echo '</div>';
    }

    protected function normalizeMeta($meta)
    {
        if (is_array($meta)) {
            return $meta;
        }
        if (is_string($meta)) {
            $decoded = json_decode($meta, true);
            if (is_array($decoded)) {
                return $decoded;
            }
        }
        return [];
    }

    protected function resolveCurrencyCode($value, string $fallback = 'USD'): string
    {
        $currency_helper = Currency::getInstance();

        if (is_string($value) || $value === null) {
            return $currency_helper->sanitizeCurrency($value ?: $fallback);
        }

        if (is_array($value)) {
            foreach (['currency', 'code', 'value', 0] as $key) {
                if (isset($value[$key]) && is_string($value[$key]) && $value[$key] !== '') {
                    return $currency_helper->sanitizeCurrency($value[$key]);
                }
            }
        }

        return $currency_helper->sanitizeCurrency($fallback);
    }
}
