<?php
/**
 * BookiFlex Payment Extension
 *
 * @package    BookiFlex
 * @subpackage Payment
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

 namespace BookiFlex\Extensions\Payment\Admin\CTL;

use BookiFlex\Core\Contract\Payment\PaymentStatus;
use BookiFlex\Core\Contract\PluginInterface;
use BookiFlex\Core\Util\Request;
use BookiFlex\Extensions\Payment\Admin\Menu\PaymentMenu;
use BookiFlex\Extensions\Payment\Admin\Transformer\PaymentTableListTransformer;
use BookiFlex\Extensions\Payment\Repository\PaymentQueryFilter;
use BookiFlex\Extensions\Payment\Service\PaymentListService;
use BookiFlex\Extensions\Payment\Util\Util;
use Brick\Money\Money;

defined( 'ABSPATH' ) || exit;

class PaymentTableList extends \WP_List_Table
{
    public const NAME = 'PAYMENT_TABLE_LIST';

    public const ITEMS_PER_PAGE_OPTION = 20;
    public const DATE_FORMAT = 'Y-m-d H:i:s';
    public const DISPLAY_DATE_FORMAT = 'Y-m-d H:i';

    private readonly PluginInterface $plugin;
    private ?array $pendingNotice = null;

    public function __construct(PluginInterface $plugin)
    {
        $this->plugin = $plugin;
        parent::__construct([
            'singular' => __('Payment', 'bookiflex'),
            'plural'   => __('Payments', 'bookiflex'),
            'ajax'     => false,
        ]);
    }

    public function get_name(): string
    {
        return self::NAME;
    }

    /**
     * Get available payment statuses
     */
    protected function get_statuses(): array
    {
        return [
            PaymentStatus::WAITING    => __('Waiting', 'bookiflex'),
            PaymentStatus::CANCELLED  => __('Cancelled', 'bookiflex'),
            PaymentStatus::PAID       => __('Paid', 'bookiflex'),
            PaymentStatus::AUTHORIZED => __('Authorized', 'bookiflex'),
            PaymentStatus::EXPIRED    => __('Expired', 'bookiflex'),
        ];
    }

    /**
     * Define table columns
     */
    public function get_columns(): array
    {
        return [
            'cb'           => '<input type="checkbox" />',
            'id'           => __('ID', 'bookiflex'),
            'first_name'   => __('Customer', 'bookiflex'),
            'amount'       => __('Amount', 'bookiflex'),
            'allocated'    => __('Allocated', 'bookiflex'),
            'status'       => __('Status', 'bookiflex'),
            'gateway_name' => __('Gateway name', 'bookiflex'),
            'created_at'   => __('Created At', 'bookiflex'),
            'updated_at'   => __('Updated At', 'bookiflex'),
            'actions'      => __('Actions', 'bookiflex'),
        ];
    }

    /**
     * Define which columns are sortable
     */
    public function get_sortable_columns(): array
    {
        return [
            'id'           => ['id', false],
            'first_name'   => ['customer', false],
            'amount'       => ['total_amount', false],
            'status'       => ['status', false],
            'gateway_name' => ['gateway_name', false],
            'created_at'   => ['created_at', true], // Default sort descending
            'updated_at'   => ['updated_at', false],
        ];
    }

    /**
     * Define default hidden columns
     */
    protected function get_default_hidden_columns(): array
    {
        return [
            'id',
            'updated_at',
        ];
    }

    /**
     * Get user's hidden columns preference
     */
    public function get_hidden_columns(): array
    {
        $hidden = get_user_option('manage' . $this->screen->id . 'columnshidden');

        if ($hidden === false) {
            $hidden = $this->get_default_hidden_columns();
        }

        return $hidden;
    }

    /**
     * Default column display method
     */
    public function column_default($item, $column_name)
    {
        switch ($column_name) {
            case 'id':
                return $item[$column_name] ?? '';
            case 'gateway_name':
                return Util::transformGatewayName($item[$column_name]) ?? '';
            default:
                return '';
        }
    }

    /**
     * Display checkbox column
     */
    protected function column_cb($item): string
    {
        return sprintf(
            '<label class="screen-reader-text" for="payment_%1$d">%2$s</label>' .
            '<input type="checkbox" name="payments[]" id="payment_%1$d" value="%1$d" />',
            $item['id'],
            $item['first_name'] . ' ' . $item['last_name']
        );
    }

    /**
     * Display customer information column
     */
    protected function column_first_name($item): string
    {
        return sprintf(
            '<span>%s %s</span><br/><a href="mailto:%s" target="_blank">%s</a>',
            $item['first_name'],
            $item['last_name'],
            $item['email'],
            $item['email']
        );
    }

    /**
     * Display amount column
     */
    protected function column_amount($item): string
    {
        return Money::ofMinor($item['total_amount'], $item['currency_code'])->formatTo('en_US');
    }

    /**
     * Display allocated column
     */
    protected function column_allocated($item): string
    {
        if (!is_array($item['allocated'])) {
            return '-';
        }

        $reservations = [];
        foreach ($item['allocated'] as $allocation) {
            $link = admin_url('admin.php?page=bookiflex-reservations&action=edit&reservation_number=' . $allocation['reservation_number']);
            $amount = Money::ofMinor($allocation['amount'], $item['currency_code'])->formatTo('en_US');
            $reservations[] = sprintf(
                '<div style="white-space: nowrap; display: inline-block;"><a href="%s" data-turbo="false">%s</a><br/>- %s</div>',
                $link,
                $allocation['reservation_number'],
                $amount
            );
        }

        return implode('', $reservations);
    }

    /**
     * Display status column with colored badge
     */
    protected function column_status($item): string
    {
        $statusText = $this->get_statuses()[$item['status']] ?? $item['status'];
        $statusVariant = $this->getStatusVariant($item['status']);

        return sprintf('<sl-badge variant="%s">%s</sl-badge>', $statusVariant, $statusText);
    }

    /**
     * Get status variant for styling
     */
    private function getStatusVariant(string $status): string
    {
        return match ($status) {
            PaymentStatus::WAITING => 'warning',
            PaymentStatus::PAID => 'success',
            PaymentStatus::CANCELLED => 'danger',
            PaymentStatus::EXPIRED => 'neutral',
            PaymentStatus::AUTHORIZED => 'primary',
            default => 'primary',
        };
    }

    /**
     * Display created at column
     */
    protected function column_created_at($item): string
    {
        $dateTime = \DateTimeImmutable::createFromFormat(self::DATE_FORMAT, $item['created_at']);
        return $dateTime->format(self::DISPLAY_DATE_FORMAT);
    }

    /**
     * Display updated at column
     */
    protected function column_updated_at($item): string
    {
        if (!$item['updated_at']) {
            return '-';
        }

        $dateTime = \DateTimeImmutable::createFromFormat(self::DATE_FORMAT, $item['updated_at']);
        return $dateTime->format(self::DISPLAY_DATE_FORMAT);
    }

    /**
     * Display actions column
     */
    protected function column_actions($item): string
    {
        return sprintf(
            '<sl-button size="small" data-action="show-payment-details" data-id="%s" data-turbo="false">' .
            '<sl-icon slot="prefix" name="credit-card-2-front" label="Show details"></sl-icon>%s</sl-button>',
            $item['id'],
            _x('Details', 'Button for showing payment details', 'bookiflex')
        );
    }

    /**
     * Get primary column for mobile display
     */
    public function get_primary_column_name(): string
    {
        return 'first_name';
    }

    /**
     * Prepare table items for display
     */
    public function prepare_items(): void
    {
        // Process bulk actions before preparing items
        $this->process_bulk_action();

        // Set up column headers
        $columns = $this->get_columns();
        $hidden = $this->get_hidden_columns();
        $sortable = $this->get_sortable_columns();
        $this->_column_headers = [$columns, $hidden, $sortable];

        // Get service and transformer from container
        $service = $this->plugin->getContainer()->get(PaymentListService::class);
        $transformer = new PaymentTableListTransformer();

        // Pagination setup
        $per_page = $this->get_items_per_page(PaymentMenu::PER_PAGE_FIELD, self::ITEMS_PER_PAGE_OPTION);
        $current_page = $this->get_pagenum();

        // Create filter from request - explicitly get each parameter
        $filter = new PaymentQueryFilter(
            status: Request::getKey('status') ?: null,
            customerId: Request::getInt('client_id') ?: null,
            searchTerm: Request::getString('s') ?: null,
            orderBy: Request::getKey('orderby', 'created_at'),
            order: Request::getKey('order', 'DESC'),
            limit: $per_page,
            offset: max(0, ($current_page - 1) * $per_page),
        );

        // Get enriched data from service
        $enrichedData = $service->getPayments($filter);

        // Transform for display
        $this->items = $transformer->transform($enrichedData);

        // Count total items
        $total_items = $service->countPayments($filter);

        // Set pagination
        $this->set_pagination_args([
            'total_items' => $total_items,
            'per_page'    => $per_page,
            'total_pages' => (int) ceil($total_items / $per_page),
        ]);
    }

    /**
     * Display message when no items found
     */
    public function no_items(): void
    {
        echo esc_html__('No payments available.', 'bookiflex');
    }

    /**
     * Get status filter links for table navigation with counts
     */
    public function get_views(): array
    {
        $status_links = [];
        $statuses = $this->get_statuses();
        $pageSlug = Request::getKey('page');
        $currentStatus = Request::getString('status');
        $baseUrl = admin_url('admin.php');

        // Get service
        $service = $this->plugin->getContainer()->get(PaymentListService::class);

        // Create filter WITHOUT status to get counts across all statuses - explicitly get each parameter
        $filter = new PaymentQueryFilter(
            status: null, // No status filter for counts
            customerId: Request::getInt('client_id') ?: null,
            searchTerm: Request::getString('s') ?: null,
            orderBy: 'created_at',
            order: 'DESC',
            limit: 0,
            offset: 0,
        );

        // Get counts for each status
        $status_counts = $service->getStatusCounts($filter);
        $total_count = array_sum($status_counts);

        // All payments link with total count
        $allUrl = add_query_arg('page', $pageSlug, $baseUrl);
        $allClass = $currentStatus === '' ? ' class="current"' : '';
        $status_links['all'] = sprintf(
            '<a href="%s" aria-current="page"%s>%s <span class="count">(%d)</span></a>',
            esc_url($allUrl),
            $allClass,
            esc_html__('All', 'bookiflex'),
            $total_count
        );

        // Individual status links with counts
        foreach ($statuses as $status => $label) {
            $count = $status_counts[$status] ?? 0;

            // Skip statuses with 0 count (optional - you can remove this if to show all statuses)
            if ($count === 0) {
                continue;
            }

            $statusUrl = add_query_arg(
                [
                    'page'   => $pageSlug,
                    'status' => $status,
                ],
                $baseUrl
            );
            $currentClass = ($currentStatus === $status) ? ' class="current"' : '';
            $css_class = 'status-' . strtolower($status);

            $status_links[$css_class] = sprintf(
                '<a href="%s"%s>%s <span class="count">(%d)</span></a>',
                esc_url($statusUrl),
                $currentClass,
                esc_html($label),
                $count
            );
        }

        return $status_links;
    }

    /**
     * Define bulk actions
     */
    public function get_bulk_actions(): array
    {
        return [
            'delete' => __('Delete', 'bookiflex'),
        ];
    }

    /**
     * Process bulk actions
     */
    public function process_bulk_action(): void
    {
        // Check if bulk action is being performed
        if ('delete' !== $this->current_action()) {
            return;
        }

        // Verify nonce for security
        if (!wp_verify_nonce(Request::getNonce(), 'bulk-payments')) {
            wp_die(esc_html__('Security check failed', 'bookiflex'));
        }

        // Check user permissions
        if (!current_user_can('manage_options')) {
            wp_die(esc_html__('You do not have permission to delete payments', 'bookiflex'));
        }

        // Get selected payment IDs - already sanitized as positive integers
        $payment_ids = Request::getIntArray('payments');

        if (empty($payment_ids)) {
            $this->add_admin_notice('error', __('No payments selected for deletion', 'bookiflex'));
            return;
        }

        // Perform deletion via service
        $result = $this->delete_payments($payment_ids);
        $deleted_count = $result['deleted'];

        if ($deleted_count > 0) {
            /* translators: %d: number of payments deleted */
            $message = _n(
                '%d payment deleted successfully',
                '%d payments deleted successfully',
                $deleted_count,
                'bookiflex'
            );
            $message = sprintf($message, $deleted_count);
            $this->add_admin_notice('success', $message);
        } else {
            $this->add_admin_notice('error', __('Failed to delete payments', 'bookiflex'));
        }
    }

    /**
     * Delete payments via service
     */
    private function delete_payments(array $payment_ids): array
    {
        $service = $this->plugin->getContainer()->get(PaymentListService::class);
        return $service->deletePayments($payment_ids);
    }

    /**
     * Add admin notice
     */
    private function add_admin_notice(string $type, string $message): void
    {
        $this->plugin->addAction('admin_notices', [$this, 'displayAdminNotice']);
        $this->pendingNotice = ['type' => $type, 'message' => $message];
    }

    /**
     * Display pending admin notice
     */
    public function displayAdminNotice(): void
    {
        if (!isset($this->pendingNotice)) {
            return;
        }

        $class = $this->pendingNotice['type'] === 'error' ? 'notice-error' : 'notice-success';
        printf(
            '<div class="notice %s is-dismissible"><p>%s</p></div>',
            esc_attr($class),
            esc_html($this->pendingNotice['message'])
        );

        unset($this->pendingNotice);
    }

}
