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

declare(strict_types=1);

namespace BookiFlex\Core\Admin\CTL;

use BookiFlex\Core\Admin\Menu\ReservationMenu;
use BookiFlex\Core\Admin\Transformer\ReservationTableListTransformer;
use BookiFlex\Core\Contract\PluginInterface;
use BookiFlex\Core\Model\Reservation\ReservationStatus;
use BookiFlex\Core\Repository\ReservationQueryFilter;
use BookiFlex\Core\Service\Reservation\ReservationListService;
use BookiFlex\Core\Util\Request;

defined( 'ABSPATH' ) || exit;

class ReservationTableList extends \WP_List_Table
{
    public const NAME = 'RESERVATION_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' => __('Reservation', 'bookiflex'),
            'plural'   => __('Reservations', 'bookiflex'),
            'ajax'     => false,
        ]);
    }

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

    /**
     * Get available reservation statuses
     */
    protected function get_statuses(): array
    {
        return [
            ReservationStatus::STATUS_WAITING_PAYMENT      => __('Waiting for payment', 'bookiflex'),
            ReservationStatus::STATUS_WAITING_CONFIRMATION => __('Need confirmation', 'bookiflex'),
            ReservationStatus::STATUS_OVERDUE              => __('Need confirmation', 'bookiflex'),
            ReservationStatus::STATUS_CONFIRMED            => __('Confirmed', 'bookiflex'),
            ReservationStatus::STATUS_CANCELLED            => __('Cancelled', 'bookiflex'),
            ReservationStatus::STATUS_NO_SHOW              => __('No Show', 'bookiflex'),
            ReservationStatus::STATUS_IN_HOUSE             => __('In House', 'bookiflex'),
            ReservationStatus::STATUS_COMPLETED            => __('Completed', 'bookiflex'),
        ];
    }

    /**
     * Define table columns
     */
    public function get_columns(): array
    {
        return [
            'cb'               => '<input type="checkbox" />',
            'created_at'           => __('Number', 'bookiflex'),
            'first_name'       => __('Customer', 'bookiflex'),
            'status'           => __('Status', 'bookiflex'),
            'language'         => __('Language', 'bookiflex'),
            'check_in_time'    => __('Check-In', 'bookiflex'),
//            'payment_type'     => __('Payment type', 'bookiflex'),
	        'accommodation_name' => __('Rental unit', 'bookiflex'),
            'total_amount'     => __('Total amount', 'bookiflex'),
            'prepayment'       => __('Payment', 'bookiflex'),
            'special_request'  => __('Special request', 'bookiflex'),
            'is_group'         => __('Group', 'bookiflex'),
//            'created_at'       => __('Created At', 'bookiflex'),
            'updated_at'       => __('Updated At', 'bookiflex'),
            'actions'          => __('Actions', 'bookiflex'),
        ];
    }

    /**
     * Define which columns are sortable
     */
    protected function get_sortable_columns(): array
    {
        return [
            'created_at'    => ['created_at', true],
            'first_name'    => ['customer', false],
            'status'        => ['status', false],
            'language'      => ['language', false],
            'check_in_time' => ['check_in_date', false],
//            'payment_type'  => ['payment_type', false],
            'total_amount'  => ['total_amount', 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 [
            'language',
            'special_request',
            'is_group',
//            'created_at',
            '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 'language':
            case 'special_request':
            case 'created_at':
            case 'updated_at':
                return $item[$column_name] ?? '';
            default:
                return '';
        }
    }

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

    /**
     * Display reservation created_at column
     */
    protected function column_created_at($item): string
    {
        return sprintf(
            '<strong title="ID: %s">%s</strong><br/>%s',
            $item['id'],
            $item['number'],
            $item['created_at_display']
        );
    }

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

    /**
     * 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) {
            ReservationStatus::STATUS_WAITING_PAYMENT => 'warning',
            ReservationStatus::STATUS_CONFIRMED => 'success',
            ReservationStatus::STATUS_COMPLETED => 'neutral',
            ReservationStatus::STATUS_CART,
            ReservationStatus::STATUS_OVERDUE,
            ReservationStatus::STATUS_CANCELLED,
            ReservationStatus::STATUS_NO_SHOW => 'danger',
            default => 'primary',
        };
    }

    /**
     * Display check-in time column
     */
    protected function column_check_in_time($item): string
    {
        /* translators: %d: number of nights */
        $nightsText = _n('%d night', '%d nights', $item['length_of_stay'], 'bookiflex');

        return $item['check_in_datetime']->format(self::DISPLAY_DATE_FORMAT) . '<br/>' .
            sprintf($nightsText, $item['length_of_stay']);
    }

    /**
     * Display payment type column
     */
    protected function column_accommodation_name($item): string
    {
	    return $item['accommodation_name'] ?? '';
    }

    /**
     * Display total amount column
     */
    protected function column_total_amount($item): string
    {
        return $item['total_amount_formatted'];
    }

    /**
     * Display payment type column
     */
    protected function column_prepayment($item): string
    {
        if ($item['prepayment']->isZero()) {
            return __('No prepayment', 'bookiflex');
        }

        return sprintf(
            '%s<br/><i>%s of %s</i>',
	        $item['payment_type'] ?? '',
            $item['paid']->formatTo('en'),
            $item['prepayment']->formatTo('en')
        );
    }

    /**
     * Display group status column
     */
    protected function column_is_group($item): string
    {
        if ($item['is_group'] === 'Yes') {
            $link = admin_url('admin.php?page=bflex_reservations&group_id=' . $item['group_id']);
            return sprintf(
                '<span class="dashicons dashicons-yes"></span> <a href="%s">(%d)</a>',
                $link,
                $item['reservation_count']
            );
        }

        return '<span class="dashicons dashicons-no"></span>';
    }

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

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

    /**
     * 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(ReservationListService::class);
        $transformer = new ReservationTableListTransformer();

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

        // Create filter from request - explicitly get each parameter
        $filter = new ReservationQueryFilter(
            statuses: Request::getKey('status') ? [(string) Request::getKey('status')] : null,
            customerId: Request::getInt('customer_id') ?: null,
            groupId: Request::getInt('group_id') ?: null,
            searchTerm: Request::getString('s') ?: null,
            reservationNumber: Request::getString('reservation_number') ?: 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->getReservations($filter);

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

        // Count total items
        $total_items = $service->countReservations($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 reservations 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 counts for each status
        $status_counts = $this->get_status_counts();
        $total_count = array_sum($status_counts);

        // All reservations 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)
            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;
    }

    /**
     * Get count of reservations for each status
     */
    private function get_status_counts(): array
    {
        $service = $this->plugin->getContainer()->get(ReservationListService::class);

        // Create filter from request without status constraint - explicitly get each parameter
        $filter = new ReservationQueryFilter(
            statuses: null, // No status filter for counts
            customerId: Request::getInt('customer_id') ?: null,
            groupId: Request::getInt('group_id') ?: null,
            searchTerm: Request::getString('s') ?: null,
            reservationNumber: Request::getString('reservation_number') ?: null,
            orderBy: 'created_at',
            order: 'DESC',
            limit: 0,
            offset: 0,
        );

        $counts = $service->getStatusCounts($filter);

        // Ensure all statuses are present in the array, even with 0 count
        $all_statuses = array_keys($this->get_statuses());
        foreach ($all_statuses as $status) {
            if (!isset($counts[$status])) {
                $counts[$status] = 0;
            }
        }

        return $counts;
    }

    /**
     * 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-reservations')) {
            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 reservations', 'bookiflex'));
        }

        // Get selected reservation IDs - already sanitized as positive integers
        $reservation_ids = Request::getIntArray('reservations');

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

        // Perform deletion
        $deleted_count = $this->delete_reservations($reservation_ids);

        if ($deleted_count > 0) {
            /* translators: %d: number of reservations deleted */
            $message = _n(
                '%d reservation deleted successfully',
                '%d reservations 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 reservations', 'bookiflex'));
        }
    }

    /**
     * Delete reservations from database
     */
    private function delete_reservations(array $reservation_ids): int
    {
        if (empty($reservation_ids)) {
            return 0;
        }

		/** @var ReservationListService $service */
        $service = $this->plugin->getContainer()->get(ReservationListService::class);

        // Delete via service (handles fetching details before deletion)
        $result = $service->deleteReservations($reservation_ids);

        return $result['deleted'];
    }

    /**
     * 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);
    }
}
