<?php
/**
 * Splittable table layouts (uniform 3×2 or custom 4+2).
 *
 * @package Maca_MenuList
 */

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

/**
 * Parse admin input into seat counts per slot (must sum to total seats).
 *
 * @param string $raw         e.g. "4,2" or "4+2".
 * @param int    $total_seats Table seat count.
 * @return array<int, int>|WP_Error
 */
function maca_menulist_parse_split_slot_sizes_input($raw, $total_seats) {
    $total_seats = max(1, (int) $total_seats);
    $raw = trim((string) $raw);

    if ($raw === '') {
        return new WP_Error('empty', __('Ange platser per del, t.ex. 4,2.', 'maca-restu-pro'));
    }

    $parts = preg_split('/[\s,++]+/', $raw, -1, PREG_SPLIT_NO_EMPTY);
    $sizes = array();

    foreach ($parts as $part) {
        if (!preg_match('/^\d+$/', $part)) {
            return new WP_Error('invalid', __('Ogiltig fördelning. Använd tal separerade med komma, t.ex. 4,2.', 'maca-restu-pro'));
        }

        $value = (int) $part;
        if ($value < 1) {
            return new WP_Error('invalid', __('Varje del måste ha minst 1 plats.', 'maca-restu-pro'));
        }

        $sizes[] = $value;
    }

    if (count($sizes) < 1 || count($sizes) > 26) {
        return new WP_Error('invalid', __('Antal delar måste vara mellan 1 och 26.', 'maca-restu-pro'));
    }

    $sum = array_sum($sizes);
    if ($sum !== $total_seats) {
        return new WP_Error(
            'sum_mismatch',
            sprintf(
                /* translators: 1: sum of parts, 2: table seats */
                __('Delarna blir %1$d platser totalt men bordet har %2$d platser. Justera fördelningen.', 'maca-restu-pro'),
                $sum,
                $total_seats
            )
        );
    }

    return $sizes;
}

/**
 * JSON storage for custom slot sizes.
 *
 * @param array<int, int> $sizes Seat counts per slot.
 * @return string
 */
function maca_menulist_encode_split_slot_sizes(array $sizes) {
    $clean = array();

    foreach ($sizes as $size) {
        $clean[] = max(1, (int) $size);
    }

    return wp_json_encode($clean);
}

/**
 * Decode custom slot sizes from a table row.
 *
 * @param object|null $table Table row.
 * @return array<int, int>
 */
function maca_menulist_decode_split_slot_sizes($table) {
    if (!is_object($table) || empty($table->split_slot_sizes)) {
        return array();
    }

    $decoded = json_decode((string) $table->split_slot_sizes, true);

    if (!is_array($decoded)) {
        return array();
    }

    $sizes = array();

    foreach ($decoded as $size) {
        $sizes[] = max(1, (int) $size);
    }

    return $sizes;
}

/**
 * Whether the table uses a custom (non-uniform) split layout.
 *
 * @param object|null $table Table row.
 * @return bool
 */
function maca_menulist_table_has_custom_split_layout($table) {
    return count(maca_menulist_decode_split_slot_sizes($table)) > 0;
}

/**
 * Decode JSON seat sizes (table or day-split row).
 *
 * @param string $json JSON array string.
 * @return array<int, int>
 */
function maca_menulist_decode_split_slot_sizes_json($json) {
    if ($json === '') {
        return array();
    }

    $decoded = json_decode($json, true);

    if (!is_array($decoded)) {
        return array();
    }

    $sizes = array();

    foreach ($decoded as $size) {
        $sizes[] = max(1, (int) $size);
    }

    return $sizes;
}

/**
 * Label for a capacity list, e.g. 4+2 or 3×2.
 *
 * @param array<int, int> $capacities Seat counts per slot.
 * @return string
 */
function maca_menulist_format_capacities_layout_label($capacities) {
    if (empty($capacities)) {
        return '';
    }

    $unique = array_unique(array_map('intval', $capacities));

    if (count($unique) === 1) {
        return count($capacities) . '×' . (int) $capacities[0];
    }

    return implode('+', array_map('strval', $capacities));
}

/**
 * Seat capacity per share slot (e.g. [4, 2] or [2, 2, 2]).
 *
 * @param object|null $table Table row.
 * @param string      $date  Optional date Y-m-d for day-specific layout.
 * @return array<int, int>
 */
function maca_menulist_get_table_split_capacities($table, $date = '') {
    if (!maca_menulist_table_is_splittable($table)) {
        return array();
    }

    $date = sanitize_text_field($date);
    if (
        $date !== ''
        && preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)
        && function_exists('maca_menulist_is_table_split_for_date')
        && maca_menulist_is_table_split_for_date((int) $table->id, $date)
    ) {
        $day_row = maca_menulist_get_table_day_split_row((int) $table->id, $date);
        if ($day_row && !empty($day_row->split_slot_sizes)) {
            $day_sizes = maca_menulist_decode_split_slot_sizes_json((string) $day_row->split_slot_sizes);
            if (!empty($day_sizes)) {
                return $day_sizes;
            }
        }
    }

    $custom = maca_menulist_decode_split_slot_sizes($table);
    if (!empty($custom)) {
        return $custom;
    }

    $seats = max(1, (int) $table->seats);
    $split = is_object($table) && isset($table->split_party_size) ? (int) $table->split_party_size : 2;
    $split = max(1, min($seats, $split));
    $slot_count = (int) max(1, floor($seats / $split));
    $capacities = array();

    for ($i = 0; $i < $slot_count; $i++) {
        $capacities[] = $split;
    }

    return $capacities;
}

/**
 * Capacity for one slot letter (a = first, b = second, …).
 *
 * @param object|null $table Table row.
 * @param string      $slot  Slot letter.
 * @param string      $date  Optional date Y-m-d.
 * @return int
 */
function maca_menulist_table_split_slot_capacity($table, $slot, $date = '') {
    $capacities = maca_menulist_get_table_split_capacities($table, $date);
    $letters = maca_menulist_get_table_split_slot_letters($table, $date);
    $slot = maca_menulist_normalize_split_slot($slot);
    $index = array_search($slot, $letters, true);

    if ($index === false || !isset($capacities[ $index ])) {
        return 0;
    }

    return (int) $capacities[ $index ];
}

/**
 * Largest party allowed on any single slot (for error messages).
 *
 * @param object|null $table Table row.
 * @return int
 */
function maca_menulist_table_split_max_party_size($table, $date = '') {
    $capacities = maca_menulist_get_table_split_capacities($table, $date);

    if (empty($capacities)) {
        return 0;
    }

    return max($capacities);
}

/**
 * Slot letters for a splittable layout (a, b, c, …).
 *
 * @param object|null $table Table row.
 * @param string      $date  Optional date Y-m-d.
 * @return array<int, string>
 */
function maca_menulist_get_table_split_slot_letters($table, $date = '') {
    if (!maca_menulist_table_is_splittable($table)) {
        return array();
    }

    $count = count(maca_menulist_get_table_split_capacities($table, $date));
    $letters = array();

    for ($i = 0; $i < $count; $i++) {
        $letters[] = chr(97 + $i);
    }

    return $letters;
}

/**
 * Max concurrent bookings allowed on a splittable table (staff floor rules).
 *
 * @param object|null $table Table row.
 * @return int
 */
function maca_menulist_table_max_share_bookings($table, $date = '') {
    if (!maca_menulist_table_is_splittable($table)) {
        return maca_menulist_admin_floor_max_bookings_per_table();
    }

    return max(1, count(maca_menulist_get_table_split_capacities($table, $date)));
}

/**
 * Human label: "4+2" or "3×2".
 *
 * @param object|null $table Table row.
 * @return string
 */
function maca_menulist_table_split_layout_label($table, $date = '') {
    if (!maca_menulist_table_is_splittable($table)) {
        return '';
    }

    $capacities = maca_menulist_get_table_split_capacities($table, $date);

    return maca_menulist_format_capacities_layout_label($capacities);
}

/**
 * Whether bookings (plus optional extra party) fit slot capacities.
 *
 * @param array<int, int>    $capacities         Seat cap per slot.
 * @param array<int, object> $bookings           Blocking bookings.
 * @param int                $extra_party        Party to add (0 = none).
 * @param int                $exclude_booking_id Booking to ignore.
 * @return bool
 */
function maca_menulist_splittable_bookings_fit_capacities($capacities, $bookings, $extra_party = 0, $exclude_booking_id = 0) {
    if (empty($capacities)) {
        return false;
    }

    $slots = array();

    foreach ($capacities as $capacity) {
        $slots[] = array(
            'capacity' => max(1, (int) $capacity),
            'occupied' => 0,
        );
    }

    foreach ($bookings as $booking) {
        if ($exclude_booking_id > 0 && (int) $booking->id === $exclude_booking_id) {
            continue;
        }

        $remaining = max(1, (int) $booking->party_size);

        foreach ($slots as $index => $slot) {
            if ($remaining <= 0) {
                break;
            }

            $space = (int) $slot['capacity'] - (int) $slot['occupied'];
            if ($space <= 0) {
                continue;
            }

            $take = min($space, $remaining);
            $slots[ $index ]['occupied'] += $take;
            $remaining -= $take;
        }

        if ($remaining > 0) {
            return false;
        }
    }

    if ($extra_party > 0) {
        $remaining = max(1, (int) $extra_party);

        foreach ($slots as $index => $slot) {
            if ($remaining <= 0) {
                break;
            }

            $space = (int) $slot['capacity'] - (int) $slot['occupied'];
            if ($space <= 0) {
                continue;
            }

            $take = min($space, $remaining);
            $slots[ $index ]['occupied'] += $take;
            $remaining -= $take;
        }

        if ($remaining > 0) {
            return false;
        }
    }

    return true;
}

/**
 * Seat dots per slot from explicit capacities.
 *
 * @param array<int, int>    $capacities Seat cap per slot.
 * @param array<int, object> $bookings   Bookings at this time.
 * @return array<int, array{capacity: int, occupied: int}>
 */
function maca_menulist_build_floor_seat_slots_from_capacities($capacities, $bookings) {
    $slots = array();

    foreach ($capacities as $capacity) {
        $slots[] = array(
            'capacity' => max(1, (int) $capacity),
            'occupied' => 0,
        );
    }

    foreach ($bookings as $booking) {
        $remaining = max(1, (int) $booking->party_size);

        foreach ($slots as $index => $slot) {
            if ($remaining <= 0) {
                break;
            }

            $space = (int) $slot['capacity'] - (int) $slot['occupied'];
            if ($space <= 0) {
                continue;
            }

            $take = min($space, $remaining);
            $slots[ $index ]['occupied'] += $take;
            $remaining -= $take;
        }
    }

    return $slots;
}
