<?php
/**
 * Per-order payment transaction log (multiple Stripe checkouts, add-ons, bill split).
 *
 * @package Maca_Menu_List
 */

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Order payment transactions table name.
 *
 * @return string
 */
function maca_menulist_db_table_order_payments_table() {
    global $wpdb;

    return $wpdb->prefix . 'maca_table_order_payments';
}

/**
 * Ensure payment transactions table exists.
 *
 * @return void
 */
function maca_menulist_db_ensure_order_payments_table() {
    global $wpdb;

    static $ensured = false;
    if ($ensured) {
        return;
    }

    $table = maca_menulist_db_table_order_payments_table();
    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table));

    if ($exists === $table) {
        $ensured = true;
        return;
    }

    maca_menulist_db_ensure_table_order_tables();

    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE $table (
        id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
        order_id bigint(20) unsigned NOT NULL,
        payment_provider varchar(20) DEFAULT NULL,
        payment_method varchar(20) DEFAULT NULL,
        payment_external_id varchar(255) DEFAULT NULL,
        payment_amount decimal(10,2) NOT NULL DEFAULT 0,
        payment_currency varchar(3) DEFAULT 'SEK',
        payment_kind varchar(20) NOT NULL DEFAULT 'checkout',
        paid_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY  (id),
        KEY order_id (order_id),
        KEY payment_external_id (payment_external_id)
    ) $charset_collate;";

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta($sql);

    $ensured = true;
}

/**
 * Attach payment transactions to order objects.
 *
 * @param array<int, object> $orders Order rows.
 * @return array<int, object>
 */
function maca_menulist_db_attach_order_payments($orders) {
    if (empty($orders)) {
        return array();
    }

    maca_menulist_db_ensure_order_payments_table();

    global $wpdb;

    $table = maca_menulist_db_table_order_payments_table();
    $order_ids = array_map(
        static function ($order) {
            return (int) $order->id;
        },
        $orders
    );

    $placeholders = implode(',', array_fill(0, count($order_ids), '%d'));
    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    $rows = $wpdb->get_results(
        $wpdb->prepare(
            "SELECT * FROM $table WHERE order_id IN ($placeholders) ORDER BY paid_at ASC, id ASC",
            ...$order_ids
        )
    );

    $by_order = array();
    foreach ($rows as $row) {
        $order_id = (int) $row->order_id;
        if (!isset($by_order[$order_id])) {
            $by_order[$order_id] = array();
        }
        $by_order[$order_id][] = $row;
    }

    foreach ($orders as $index => $order) {
        $order_id = (int) $order->id;
        $orders[$index]->payment_transactions = isset($by_order[$order_id]) ? $by_order[$order_id] : array();
    }

    return $orders;
}

/**
 * Get payment transactions for one order.
 *
 * @param int $order_id Order ID.
 * @return array<int, object>
 */
function maca_menulist_db_get_order_payment_transactions($order_id) {
    $order_id = absint($order_id);
    if ($order_id <= 0) {
        return array();
    }

    maca_menulist_db_ensure_order_payments_table();

    global $wpdb;

    $table = maca_menulist_db_table_order_payments_table();

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    return $wpdb->get_results(
        $wpdb->prepare(
            "SELECT * FROM $table WHERE order_id = %d ORDER BY paid_at ASC, id ASC",
            $order_id
        )
    );
}

/**
 * Whether a transaction with this external ID already exists for the order.
 *
 * @param int    $order_id    Order ID.
 * @param string $external_id External ID.
 * @return bool
 */
function maca_menulist_db_order_payment_transaction_exists($order_id, $external_id) {
    $external_id = sanitize_text_field($external_id);
    if ($external_id === '') {
        return false;
    }

    maca_menulist_db_ensure_order_payments_table();

    global $wpdb;

    $table = maca_menulist_db_table_order_payments_table();

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $found = $wpdb->get_var(
        $wpdb->prepare(
            "SELECT id FROM $table WHERE order_id = %d AND payment_external_id = %s LIMIT 1",
            absint($order_id),
            $external_id
        )
    );

    return !empty($found);
}

/**
 * Calculate increment for a new transaction from order state and payment args.
 *
 * @param object               $order Order row before update.
 * @param array<string, mixed> $args  payment_amount, transaction_amount.
 * @return float
 */
function maca_menulist_calculate_order_payment_increment($order, $args) {
    if (isset($args['transaction_amount'])) {
        return round(max(0, (float) $args['transaction_amount']), 2);
    }

    $amount = isset($args['payment_amount']) ? round(max(0, (float) $args['payment_amount']), 2) : 0.0;
    $existing = round(max(0, (float) ($order->payment_amount ?? 0)), 2);

    if ($existing <= 0.009) {
        return $amount;
    }

    if ($amount <= 0) {
        return 0.0;
    }

    if ($amount + 0.009 < $existing) {
        return $amount;
    }

    return round(max(0, $amount - $existing), 2);
}

/**
 * Resolve payment_kind for a transaction.
 *
 * @param int                  $order_id Order ID.
 * @param array<string, mixed> $args     Args.
 * @return string
 */
function maca_menulist_resolve_order_payment_kind($order_id, $args) {
    if (!empty($args['payment_kind'])) {
        $kind = sanitize_key((string) $args['payment_kind']);
        if (in_array($kind, array('checkout', 'supplemental', 'bill_split', 'manual'), true)) {
            return $kind;
        }
    }

    if (!empty($args['supplemental_payment']) || !empty($args['bill_split_share'])) {
        return !empty($args['bill_split_share']) ? 'bill_split' : 'supplemental';
    }

    $existing = maca_menulist_db_get_order_payment_transactions($order_id);
    if (!empty($existing)) {
        return 'supplemental';
    }

    $provider = isset($args['payment_provider']) ? sanitize_key((string) $args['payment_provider']) : '';
    if ($provider === 'manual') {
        return 'manual';
    }

    return 'checkout';
}

/**
 * Human-readable label for payment_kind.
 *
 * @param string $kind Kind key.
 * @return string
 */
function maca_menulist_get_order_payment_kind_label($kind) {
    $kind = sanitize_key($kind);
    $labels = array(
        'checkout'     => __('Initial payment', 'maca-restu-pro'),
        'supplemental' => __('Add-on payment', 'maca-restu-pro'),
        'bill_split'   => __('Bill share', 'maca-restu-pro'),
        'manual'       => __('Manual payment', 'maca-restu-pro'),
    );

    return isset($labels[$kind]) ? $labels[$kind] : $kind;
}

/**
 * Record one payment transaction (idempotent on external_id).
 *
 * @param int                  $order_id Order ID.
 * @param array<string, mixed> $args     provider, method, external_id, currency, payment_kind, supplemental_payment.
 * @param float|null           $increment_amount Amount for this transaction only.
 * @return bool
 */
function maca_menulist_db_record_order_payment_transaction($order_id, $args, $increment_amount = null) {
    global $wpdb;

    $order_id = absint($order_id);
    if ($order_id <= 0) {
        return false;
    }

    $order = maca_menulist_db_get_table_order($order_id);
    if (!$order) {
        return false;
    }

    $increment = $increment_amount !== null
        ? round(max(0, (float) $increment_amount), 2)
        : maca_menulist_calculate_order_payment_increment($order, $args);

    if ($increment <= 0.009) {
        return false;
    }

    $external_id = isset($args['payment_external_id']) ? sanitize_text_field((string) $args['payment_external_id']) : '';
    if ($external_id !== '' && maca_menulist_db_order_payment_transaction_exists($order_id, $external_id)) {
        return true;
    }

    maca_menulist_db_ensure_order_payments_table();

    $provider = isset($args['payment_provider']) ? sanitize_key((string) $args['payment_provider']) : '';
    $method = isset($args['payment_method']) ? sanitize_key((string) $args['payment_method']) : '';
    if ($method === '' && $provider === 'stripe') {
        $method = 'online';
    }
    if ($method === '' && $provider === 'manual') {
        $method = 'manual';
    }

    $currency = isset($args['payment_currency']) ? sanitize_text_field((string) $args['payment_currency']) : maca_menulist_get_price_currency();
    $kind = maca_menulist_resolve_order_payment_kind($order_id, $args);

    $table = maca_menulist_db_table_order_payments_table();

    $inserted = $wpdb->insert(
        $table,
        array(
            'order_id' => $order_id,
            'payment_provider' => $provider !== '' ? $provider : null,
            'payment_method' => $method !== '' ? $method : null,
            'payment_external_id' => $external_id !== '' ? $external_id : null,
            'payment_amount' => $increment,
            'payment_currency' => $currency,
            'payment_kind' => $kind,
            'paid_at' => maca_menulist_wp_now_mysql(),
        ),
        array('%d', '%s', '%s', '%s', '%f', '%s', '%s', '%s')
    );

    return $inserted !== false;
}

/**
 * Format one transaction row for UI/JSON.
 *
 * @param object $tx Transaction row.
 * @param int    $number 1-based index.
 * @return array<string, mixed>
 */
function maca_menulist_format_order_payment_transaction_row($tx, $number = 1) {
    $currency = isset($tx->payment_currency) ? (string) $tx->payment_currency : '';
    $amount = round(max(0, (float) $tx->payment_amount), 2);
    $format_amount = static function ($value) use ($currency) {
        if ($currency !== '' && function_exists('maca_menulist_format_order_total')) {
            return maca_menulist_format_order_total($value, $currency);
        }

        return maca_menulist_format_price($value);
    };

    $kind = isset($tx->payment_kind) ? sanitize_key((string) $tx->payment_kind) : 'checkout';
    $method = isset($tx->payment_method) ? sanitize_key((string) $tx->payment_method) : '';

    return array(
        'number' => $number,
        'kind' => $kind,
        'kind_label' => maca_menulist_get_order_payment_kind_label($kind),
        'method' => $method,
        'method_label' => maca_menulist_get_payment_method_label($method),
        'provider' => isset($tx->payment_provider) ? sanitize_key((string) $tx->payment_provider) : '',
        'provider_label' => maca_menulist_get_payment_provider_label(isset($tx->payment_provider) ? (string) $tx->payment_provider : ''),
        'amount' => $amount,
        'amount_label' => $format_amount($amount),
        'external_id' => isset($tx->payment_external_id) ? (string) $tx->payment_external_id : '',
        'paid_at' => isset($tx->paid_at) ? (string) $tx->paid_at : '',
        'paid_at_label' => !empty($tx->paid_at) && function_exists('maca_menulist_format_payment_datetime')
            ? maca_menulist_format_payment_datetime((string) $tx->paid_at)
            : '',
    );
}

/**
 * Payment transactions payload for JSON/admin.
 *
 * @param object $order Order with optional ->payment_transactions.
 * @return array{count: int, items: array<int, array<string, mixed>>, summary_label: string, amounts_breakdown: string}
 */
function maca_menulist_build_order_payment_transactions_state($order) {
    $transactions = array();
    if (!empty($order->payment_transactions) && is_array($order->payment_transactions)) {
        $transactions = $order->payment_transactions;
    } elseif (!empty($order->id)) {
        $transactions = maca_menulist_db_get_order_payment_transactions((int) $order->id);
    }

    $items = array();
    $amount_labels = array();
    $number = 1;

    foreach ($transactions as $tx) {
        $row = maca_menulist_format_order_payment_transaction_row($tx, $number);
        $items[] = $row;
        $amount_labels[] = $row['amount_label'];
        $number++;
    }

    $count = count($items);
    $summary_label = '';

    if ($count > 1) {
        $summary_label = sprintf(
            /* translators: 1: number of payments, 2: amounts joined with + */
            _n(
                '%1$d payment: %2$s',
                '%1$d payments: %2$s',
                $count,
                'maca-restu-pro'
            ),
            $count,
            implode(' + ', $amount_labels)
        );
    } elseif ($count === 1) {
        $summary_label = $items[0]['kind_label'] . ' — ' . $items[0]['amount_label'];
    }

    return array(
        'count' => $count,
        'items' => $items,
        'summary_label' => $summary_label,
        'amounts_breakdown' => implode(' + ', $amount_labels),
    );
}

/**
 * Short summary when multiple transactions exist (for payment history list).
 *
 * @param object $order Order row.
 * @return string
 */
function maca_menulist_format_order_payment_transactions_short($order) {
    $state = maca_menulist_build_order_payment_transactions_state($order);

    if ($state['count'] <= 1) {
        return '';
    }

    return $state['summary_label'];
}

/**
 * Render HTML list of transactions (admin).
 *
 * @param object $order Order row.
 * @return string
 */
function maca_menulist_render_order_payment_transactions_html($order) {
    $state = maca_menulist_build_order_payment_transactions_state($order);

    if ($state['count'] === 0) {
        return '';
    }

    $html = '<ul class="maca-order-payment-transactions">';
    foreach ($state['items'] as $item) {
        $html .= '<li>';
        $html .= '<strong>' . esc_html(sprintf(
            /* translators: %d: payment number */
            __('Payment %d', 'maca-restu-pro'),
            (int) $item['number']
        )) . '</strong>: ';
        $html .= esc_html($item['amount_label']);
        $html .= ' — ' . esc_html($item['kind_label']);
        if ($item['method_label'] !== '—') {
            $html .= ' (' . esc_html($item['method_label']) . ')';
        }
        if ($item['paid_at_label'] !== '') {
            $html .= '<br><span class="description">' . esc_html($item['paid_at_label']) . '</span>';
        }
        if ($item['external_id'] !== '') {
            $html .= '<br><code class="maca-order-payment-external-id">' . esc_html($item['external_id']) . '</code>';
        }
        $html .= '</li>';
    }
    $html .= '</ul>';

    return $html;
}
