<?php
/**
 * Waiter profiles and table filtering for the staff order page.
 *
 * @package Maca_Menu_List
 */

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

/**
 * Whether waiter profiles can be configured (server delivery mode).
 *
 * @return bool
 */
function maca_menulist_waiters_feature_available() {
    return maca_menulist_table_order_enabled() && maca_menulist_table_order_uses_server();
}

/**
 * Whether at least one active waiter with tables exists.
 *
 * @return bool
 */
function maca_menulist_has_configured_waiters() {
    if (!maca_menulist_waiters_feature_available()) {
        return false;
    }

    foreach (maca_menulist_db_get_waiters(true) as $waiter) {
        if (!empty(maca_menulist_db_get_waiter_table_numbers((int) $waiter->id))) {
            return true;
        }
    }

    return false;
}

/**
 * Normalize table numbers for matching orders to assignments.
 *
 * @param string $value Raw table number.
 * @return string
 */
function maca_menulist_normalize_table_number($value) {
    $value = sanitize_text_field((string) $value);

    return strtolower(trim($value));
}

/**
 * Waiters for the staff UI (waiter view only).
 *
 * @return array<int, array{id:int, name:string, tables:array<int, string>}>
 */
function maca_menulist_get_waiters_for_staff_ui() {
    $waiters = array();

    foreach (maca_menulist_db_get_waiters(true) as $waiter) {
        $tables = maca_menulist_db_get_waiter_table_numbers((int) $waiter->id);
        if (empty($tables)) {
            continue;
        }

        $waiters[] = array(
            'id' => (int) $waiter->id,
            'name' => (string) $waiter->name,
            'tables' => $tables,
        );
    }

    return $waiters;
}

/**
 * Parse staff order filter from POST.
 *
 * @return array{scope:string, waiter_id:int}
 */
function maca_menulist_parse_staff_order_filter_from_request() {
    $scope = isset($_POST['staff_scope']) ? sanitize_key(wp_unslash($_POST['staff_scope'])) : 'all';
    $waiter_id = isset($_POST['staff_waiter_id']) ? absint(wp_unslash($_POST['staff_waiter_id'])) : 0;

    if ($scope !== 'waiter') {
        return array(
            'scope' => 'all',
            'waiter_id' => 0,
        );
    }

    if (!function_exists('maca_menulist_db_get_waiter')) {
        return array(
            'scope' => 'all',
            'waiter_id' => 0,
        );
    }

    $waiter = maca_menulist_db_get_waiter($waiter_id);
    if (!$waiter || !(int) $waiter->is_active) {
        return array(
            'scope' => 'all',
            'waiter_id' => 0,
        );
    }

    return array(
        'scope' => 'waiter',
        'waiter_id' => $waiter_id,
    );
}

/**
 * Parse optional table filter from staff POST (waiter drill-down).
 *
 * @return array{table_number:string,service_mode:string}
 */
function maca_menulist_parse_staff_table_filter_from_request() {
    $table_number = isset($_POST['table_number']) ? sanitize_text_field(wp_unslash($_POST['table_number'])) : '';
    $service_mode = isset($_POST['service_mode']) ? sanitize_key(wp_unslash($_POST['service_mode'])) : '';
    $walk_in = isset($_POST['staff_walk_in']) && wp_unslash($_POST['staff_walk_in']) === '1';

    if (!in_array($service_mode, array('dine_in', 'takeaway'), true)) {
        $service_mode = '';
    }

    return array(
        'table_number' => trim($table_number),
        'service_mode' => $service_mode,
        'walk_in'      => $walk_in,
    );
}

/**
 * Whether the request targets a single staff table drill-down.
 *
 * @param array{table_number:string,service_mode:string,walk_in:bool} $filter Table filter.
 * @return bool
 */
function maca_menulist_staff_table_filter_is_active(array $filter) {
    if (!empty($filter['walk_in'])) {
        return true;
    }

    if (($filter['service_mode'] ?? '') === 'takeaway') {
        return true;
    }

    return ($filter['table_number'] ?? '') !== '';
}

/**
 * Filter staff orders by table or takeaway session key.
 *
 * @param array<int, object>         $orders Orders with lines attached.
 * @param array{table_number:string,service_mode:string} $filter Table filter.
 * @return array<int, object>
 */
function maca_menulist_filter_orders_for_staff_table($orders, array $filter) {
    $table_number = isset($filter['table_number']) ? trim((string) $filter['table_number']) : '';
    $service_mode = isset($filter['service_mode']) ? sanitize_key((string) $filter['service_mode']) : '';

    if ($table_number === '' && $service_mode === '') {
        return $orders;
    }

    return array_values(
        array_filter(
            $orders,
            static function ($order) use ($table_number, $service_mode) {
                $mode = function_exists('maca_menulist_get_order_service_mode')
                    ? maca_menulist_get_order_service_mode($order)
                    : 'dine_in';

                if ($service_mode === 'takeaway') {
                    if ($mode !== 'takeaway') {
                        return false;
                    }

                    if ($table_number === '') {
                        return true;
                    }

                    $pickup = isset($order->pickup_name) ? trim((string) $order->pickup_name) : '';

                    return $pickup !== '' && $pickup === $table_number;
                }

                if ($mode === 'takeaway') {
                    return false;
                }

                return trim((string) $order->table_number) === $table_number;
            }
        )
    );
}

/**
 * Build grouped table overview for waiter staff screen.
 *
 * @param array<int, object> $orders Lightweight order rows.
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_build_staff_table_summary($orders) {
    $groups = array();

    foreach ($orders as $order) {
        $mode = function_exists('maca_menulist_get_order_service_mode')
            ? maca_menulist_get_order_service_mode($order)
            : 'dine_in';
        $status = maca_menulist_normalize_table_order_status((string) $order->status);

        if ($mode === 'takeaway') {
            $pickup = isset($order->pickup_name) ? trim((string) $order->pickup_name) : '';
            $key = 'takeaway:' . ($pickup !== '' ? $pickup : 'order-' . (int) $order->id);
            $label = $pickup !== ''
                ? sprintf(
                    /* translators: %s: guest pickup name */
                    __('Takeaway — %s', 'maca-restu-pro'),
                    $pickup
                )
                : __('Takeaway', 'maca-restu-pro');
            $table_number = '';
            $service_mode = 'takeaway';
            $filter_table = $pickup;
        } else {
            $table_number = trim((string) $order->table_number);
            if ($table_number === '') {
                $key = 'table:walk-in';
                $label = __('Active order', 'maca-restu-pro');
                $filter_table = '';
            } else {
                $key = 'table:' . $table_number;
                $label = sprintf(
                    /* translators: %s: table number */
                    __('Table %s', 'maca-restu-pro'),
                    $table_number
                );
                $filter_table = $table_number;
            }
            $service_mode = 'dine_in';
        }

        if (!isset($groups[$key])) {
            $groups[$key] = array(
                'key' => $key,
                'table_number' => $filter_table,
                'service_mode' => $service_mode,
                'walk_in' => $table_number === '' && $mode !== 'takeaway' && $key === 'table:walk-in',
                'label' => $label,
                'order_count' => 0,
                'has_ready' => false,
                'has_new' => false,
            );
        }

        $groups[$key]['order_count']++;
        if ($status === 'ready') {
            $groups[$key]['has_ready'] = true;
        }
        if (in_array($status, array('new', 'accepted'), true)) {
            $groups[$key]['has_new'] = true;
        }
    }

    $summary = array_values($groups);

    usort(
        $summary,
        static function ($a, $b) {
            if ($a['service_mode'] !== $b['service_mode']) {
                return $a['service_mode'] === 'takeaway' ? 1 : -1;
            }

            if ($a['service_mode'] === 'takeaway') {
                return strcasecmp((string) $a['label'], (string) $b['label']);
            }

            $a_num = is_numeric($a['table_number']) ? (float) $a['table_number'] : (string) $a['table_number'];
            $b_num = is_numeric($b['table_number']) ? (float) $b['table_number'] : (string) $b['table_number'];

            if (is_float($a_num) && is_float($b_num)) {
                return $a_num <=> $b_num;
            }

            return strnatcasecmp((string) $a['table_number'], (string) $b['table_number']);
        }
    );

    return $summary;
}

/**
 * Whether an order belongs to a waiter's assigned tables.
 *
 * @param object $order     Order row.
 * @param int    $waiter_id Waiter ID.
 * @return bool
 */
function maca_menulist_order_visible_to_waiter($order, $waiter_id) {
    $waiter_id = absint($waiter_id);
    if ($waiter_id <= 0 || !$order) {
        return false;
    }

    $assigned = maca_menulist_db_get_waiter_table_numbers($waiter_id);
    if (empty($assigned)) {
        return false;
    }

    $order_table = maca_menulist_normalize_table_number((string) $order->table_number);
    if ($order_table === '') {
        return false;
    }

    foreach ($assigned as $table_number) {
        if (maca_menulist_order_table_matches_waiter_assignment($order_table, $table_number)) {
            return true;
        }
    }

    return false;
}

/**
 * Whether an order table label matches a waiter's assigned table (incl. day splits).
 *
 * @param string $order_table    Normalized order table_number.
 * @param string $assigned_table Waiter's assigned table number.
 * @return bool
 */
function maca_menulist_order_table_matches_waiter_assignment($order_table, $assigned_table) {
    $order_table = maca_menulist_normalize_table_number((string) $order_table);
    $assigned_table = maca_menulist_normalize_table_number((string) $assigned_table);

    if ($order_table === '' || $assigned_table === '') {
        return false;
    }

    if ($order_table === $assigned_table) {
        return true;
    }

    if (!function_exists('maca_menulist_db_get_booking_tables')) {
        return false;
    }

    $date = function_exists('maca_menulist_guest_order_table_date')
        ? maca_menulist_guest_order_table_date()
        : wp_date('Y-m-d');

    foreach (maca_menulist_db_get_booking_tables(true) as $table) {
        $base = maca_menulist_normalize_table_number((string) $table->table_number);

        if ($base === '' || $base !== $assigned_table) {
            continue;
        }

        $table_id = isset($table->id) ? absint($table->id) : 0;

        if (
            $table_id <= 0
            || !function_exists('maca_menulist_is_table_split_for_date')
            || !maca_menulist_is_table_split_for_date($table_id, $date)
            || !function_exists('maca_menulist_get_table_split_slot_letters')
        ) {
            continue;
        }

        foreach (maca_menulist_get_table_split_slot_letters($table, $date) as $slot) {
            $split_label = function_exists('maca_menulist_format_split_table_number')
                ? maca_menulist_format_split_table_number($base, $slot)
                : $base . $slot;
            $split_label = maca_menulist_normalize_table_number($split_label);

            if ($split_label !== '' && $split_label === $order_table) {
                return true;
            }
        }
    }

    return false;
}

/**
 * Filter orders for a waiter profile.
 *
 * @param array<int, object> $orders    Orders with lines.
 * @param int                $waiter_id Waiter ID.
 * @return array<int, object>
 */
function maca_menulist_filter_orders_for_waiter($orders, $waiter_id) {
    if (!is_array($orders)) {
        return array();
    }

    $waiter_id = absint($waiter_id);
    if ($waiter_id <= 0) {
        return $orders;
    }

    return array_values(array_filter(
        $orders,
        static function ($order) use ($waiter_id) {
            return maca_menulist_order_visible_to_waiter($order, $waiter_id);
        }
    ));
}

/**
 * Apply staff scope filter to orders.
 *
 * @param array<int, object> $orders Orders.
 * @param string             $scope  all|waiter.
 * @param int                $waiter_id Waiter ID when scope is waiter.
 * @return array<int, object>
 */
function maca_menulist_filter_orders_for_staff_scope($orders, $scope, $waiter_id = 0) {
    if ($scope !== 'waiter' || $waiter_id <= 0) {
        return is_array($orders) ? $orders : array();
    }

    return maca_menulist_filter_orders_for_waiter($orders, $waiter_id);
}
