<?php
/**
 * Site chatbot index builders (menu, hours, events, booking, etc.).
 *
 * @package Maca_Menu_List
 */

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

require_once MACA_MENULIST_PLUGIN_DIR . 'includes/site-chat.php';

/**
 * Normalize one document record.
 *
 * @param array<string, mixed> $doc Document.
 * @return array<string, mixed>|null
 */
function maca_menulist_site_chat_normalize_document($doc) {
    if (!is_array($doc)) {
        return null;
    }

    $content = isset($doc['content']) ? trim((string) $doc['content']) : '';
    $chunk_key = isset($doc['chunk_key']) ? sanitize_text_field((string) $doc['chunk_key']) : '';

    if ($content === '' || $chunk_key === '') {
        return null;
    }

    $meta = isset($doc['meta']) && is_array($doc['meta']) ? $doc['meta'] : array();

    return array(
        'chunk_key' => $chunk_key,
        'source_type' => isset($doc['source_type']) ? sanitize_key((string) $doc['source_type']) : 'general',
        'source_id' => isset($doc['source_id']) ? sanitize_text_field((string) $doc['source_id']) : '',
        'lang' => isset($doc['lang']) ? sanitize_text_field((string) $doc['lang']) : '',
        'title' => isset($doc['title']) ? sanitize_text_field((string) $doc['title']) : '',
        'content' => $content,
        'meta_json' => wp_json_encode($meta),
    );
}

/**
 * Collect all index documents from configured sources.
 *
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_site_chat_collect_documents() {
    $documents = array();

    $collectors = array(
        'maca_menulist_site_chat_collect_hours_documents',
        'maca_menulist_site_chat_collect_footer_documents',
        'maca_menulist_site_chat_collect_booking_documents',
        'maca_menulist_site_chat_collect_menu_documents',
        'maca_menulist_site_chat_collect_campaign_documents',
        'maca_menulist_site_chat_collect_event_documents',
        'maca_menulist_site_chat_collect_news_documents',
        'maca_menulist_site_chat_collect_wp_page_documents',
    );

    foreach ($collectors as $collector) {
        if (!function_exists($collector)) {
            continue;
        }

        $batch = call_user_func($collector);

        if (!is_array($batch) || empty($batch)) {
            continue;
        }

        foreach ($batch as $doc) {
            $normalized = maca_menulist_site_chat_normalize_document($doc);

            if ($normalized) {
                $documents[] = $normalized;
            }
        }
    }

    return $documents;
}

/**
 * Build plain-text lines for weekly opening hours.
 *
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_site_chat_collect_hours_documents() {
    if (!function_exists('maca_menulist_get_booking_hours')) {
        return array();
    }

    $hours = maca_menulist_get_booking_hours();
    $labels = maca_menulist_weekday_labels();
    $day_order = maca_menulist_get_opening_hours_day_order(true);
    $lines = array(
        __('Regular opening hours:', 'maca-restu-pro'),
    );

    foreach ($day_order as $day) {
        $label = isset($labels[ $day ]) ? (string) $labels[ $day ] : (string) $day;
        $day_hours = isset($hours[ $day ]) ? maca_menulist_normalize_stored_day_hours($hours[ $day ]) : maca_menulist_normalize_stored_day_hours(array('closed' => true));

        if (!empty($day_hours['closed'])) {
            $lines[] = $label . ': ' . __('Closed', 'maca-restu-pro');
            continue;
        }

        $schedule = maca_menulist_build_bookable_hours_result($day_hours['windows']);
        $time_text = maca_menulist_format_opening_hours_schedule_text($schedule, '');

        $recurring = array();

        foreach (maca_menulist_get_display_recurring_exceptions_for_weekday($day) as $exception) {
            $line = maca_menulist_format_opening_hours_recurring_line($exception);

            if ($line !== '') {
                $recurring[] = $line;
            }
        }

        $entry = $label . ': ' . $time_text;

        if (!empty($recurring)) {
            $entry .= ' (' . implode('; ', $recurring) . ')';
        }

        $lines[] = $entry;
    }

    $documents = array(
        array(
            'chunk_key' => 'hours:weekly',
            'source_type' => 'hours',
            'source_id' => 'weekly',
            'title' => __('Opening hours', 'maca-restu-pro'),
            'content' => implode("\n", $lines),
            'meta' => array('url' => ''),
        ),
    );

    $from = wp_date('Y-m-d');
    $to = function_exists('maca_menulist_wp_now_modify')
        ? maca_menulist_wp_now_modify('+90 days', 'Y-m-d')
        : wp_date('Y-m-d', strtotime('+90 days'));

    $exception_lines = array(__('Upcoming schedule exceptions:', 'maca-restu-pro'));

    foreach (maca_menulist_get_opening_hours_display_exceptions($from, $to) as $exception) {
        $row = maca_menulist_format_opening_hours_exception_row($exception);
        $line = trim($row['date_label'] . ': ' . $row['time_text']);

        if ($row['note'] !== '') {
            $line .= ' (' . $row['note'] . ')';
        }

        $exception_lines[] = $line;
    }

    if (count($exception_lines) > 1) {
        $documents[] = array(
            'chunk_key' => 'hours:exceptions',
            'source_type' => 'hours',
            'source_id' => 'exceptions',
            'title' => __('Opening hour exceptions', 'maca-restu-pro'),
            'content' => implode("\n", $exception_lines),
            'meta' => array('url' => ''),
        );
    }

    return $documents;
}

/**
 * Menu footer / contact chunk.
 *
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_site_chat_collect_footer_documents() {
    if (!function_exists('maca_menulist_get_menu_footer_settings')) {
        return array();
    }

    $settings = maca_menulist_get_menu_footer_settings();
    $parts = array();

    if (!empty($settings['restaurant_name'])) {
        $parts[] = __('Restaurant:', 'maca-restu-pro') . ' ' . $settings['restaurant_name'];
    }

    if (!empty($settings['address'])) {
        $parts[] = __('Address:', 'maca-restu-pro') . ' ' . $settings['address'];
    }

    if (!empty($settings['phone'])) {
        $parts[] = __('Phone:', 'maca-restu-pro') . ' ' . $settings['phone'];
    }

    if (!empty($settings['email'])) {
        $parts[] = __('Email:', 'maca-restu-pro') . ' ' . $settings['email'];
    }

    if (!empty($settings['website'])) {
        $parts[] = __('Website:', 'maca-restu-pro') . ' ' . $settings['website'];
    }

    foreach (array('allergy', 'price', 'age') as $key) {
        $text = function_exists('maca_menulist_get_menu_footer_text')
            ? trim((string) maca_menulist_get_menu_footer_text($key))
            : '';

        if ($text !== '') {
            $parts[] = $text;
        }
    }

    if (function_exists('maca_menulist_get_vat_number')) {
        $vat = maca_menulist_get_vat_number();

        if ($vat !== '') {
            $parts[] = __('VAT number:', 'maca-restu-pro') . ' ' . $vat;
        }
    }

    if (empty($parts)) {
        return array();
    }

    return array(
        array(
            'chunk_key' => 'footer:contact',
            'source_type' => 'footer',
            'source_id' => 'contact',
            'title' => __('Contact and information', 'maca-restu-pro'),
            'content' => implode("\n", $parts),
            'meta' => array('url' => home_url('/')),
        ),
    );
}

/**
 * Table booking rules (not live availability).
 *
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_site_chat_collect_booking_documents() {
    if (!function_exists('maca_menulist_table_booking_enabled') || !maca_menulist_table_booking_enabled()) {
        return array();
    }

    $parts = array(
        __('Table reservations are available on this website.', 'maca-restu-pro'),
    );

    if (function_exists('maca_menulist_get_table_booking_assignment_mode')) {
        $mode = maca_menulist_get_table_booking_assignment_mode();

        if ($mode === 'best_fit') {
            $parts[] = __('Table assignment: the system picks the best available table for your party size.', 'maca-restu-pro');
        } else {
            $parts[] = __('Table assignment: guests choose a table when booking.', 'maca-restu-pro');
        }
    }

    if (function_exists('maca_menulist_table_booking_advance_days')) {
        $parts[] = sprintf(
            /* translators: %d: number of days */
            __('Bookings can be made up to %d days in advance.', 'maca-restu-pro'),
            maca_menulist_table_booking_advance_days()
        );
    }

    if (function_exists('maca_menulist_table_booking_slot_duration')) {
        $parts[] = sprintf(
            /* translators: %d: minutes */
            __('Each booking slot lasts about %d minutes.', 'maca-restu-pro'),
            maca_menulist_table_booking_slot_duration()
        );
    }

    if (function_exists('maca_menulist_table_booking_waitlist_enabled') && maca_menulist_table_booking_waitlist_enabled()) {
        $parts[] = __('When fully booked, guests can join a waitlist by email.', 'maca-restu-pro');
    }

    if (function_exists('maca_menulist_table_booking_guest_cancel_enabled') && maca_menulist_table_booking_guest_cancel_enabled()) {
        $parts[] = __('Guests can cancel confirmed bookings using the link in the confirmation email.', 'maca-restu-pro');
    }

    $notice = trim((string) get_option('maca_menulist_table_booking_arrival_notice', ''));

    if ($notice !== '') {
        $parts[] = __('Arrival information:', 'maca-restu-pro') . ' ' . $notice;
    }

    $parts[] = __('To check live availability or book a table, use the booking form on the website — the assistant cannot see real-time free tables.', 'maca-restu-pro');

    $booking_url = maca_menulist_site_chat_find_booking_page_url();
    if ($booking_url === '') {
        $booking_url = home_url('/');
    }

    return array(
        array(
            'chunk_key' => 'booking:rules',
            'source_type' => 'booking',
            'source_id' => 'rules',
            'title' => __('Table booking', 'maca-restu-pro'),
            'content' => implode("\n", $parts),
            'meta' => array('url' => $booking_url),
        ),
    );
}

/**
 * Active menu dishes (website visibility).
 *
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_site_chat_collect_menu_documents() {
    if (!function_exists('maca_menulist_get_grouped_dishes') || !maca_menulist_is_public_dishes_mode()) {
        return array();
    }

    $documents = array();
    $grouped = maca_menulist_get_grouped_dishes(
        array(
            'qr_schedule' => false,
            'takeaway_menu' => false,
        )
    );
    $menu_url = maca_menulist_site_chat_find_menu_page_url();

    foreach ($grouped as $group) {
        $category = $group['category'];
        $category_name = isset($category->name) ? (string) $category->name : '';

        if (isset($category->name_en) && (string) $category->name_en !== '') {
            $category_name = maca_menulist_get_bilingual_field($category_name, (string) $category->name_en);
        }

        foreach ($group['dishes'] as $dish) {
            $dish_id = (int) $dish->id;
            $title = isset($dish->title) ? (string) $dish->title : '';

            if (isset($dish->title_en) && (string) $dish->title_en !== '') {
                $title = maca_menulist_get_bilingual_field($title, (string) $dish->title_en);
            }

            $lines = array(
                __('Category:', 'maca-restu-pro') . ' ' . $category_name,
                __('Dish:', 'maca-restu-pro') . ' ' . $title,
            );

            $description = isset($dish->description) ? trim((string) $dish->description) : '';

            if (isset($dish->description_en) && trim((string) $dish->description_en) !== '') {
                $description = maca_menulist_get_bilingual_field($description, trim((string) $dish->description_en));
            }

            if ($description !== '') {
                $lines[] = __('Description:', 'maca-restu-pro') . ' ' . $description;
            }

            if (isset($dish->price)) {
                $lines[] = __('Price:', 'maca-restu-pro') . ' ' . maca_menulist_format_price($dish->price);
            }

            if (!empty($dish->vat_code)) {
                $lines[] = __('VAT type:', 'maca-restu-pro') . ' ' . (string) $dish->vat_code;
            }

            if (!empty($dish->allergens) && is_array($dish->allergens)) {
                $allergen_names = array();

                foreach ($dish->allergens as $allergen) {
                    $name = isset($allergen->name) ? (string) $allergen->name : '';

                    if (isset($allergen->name_en) && (string) $allergen->name_en !== '') {
                        $name = maca_menulist_get_bilingual_field($name, (string) $allergen->name_en);
                    }

                    if ($name !== '') {
                        $allergen_names[] = $name;
                    }
                }

                if (!empty($allergen_names)) {
                    $lines[] = __('Allergens:', 'maca-restu-pro') . ' ' . implode(', ', $allergen_names);
                }
            }

            $documents[] = array(
                'chunk_key' => 'dish:' . $dish_id,
                'source_type' => 'dish',
                'source_id' => (string) $dish_id,
                'title' => $title,
                'content' => implode("\n", $lines),
                'meta' => array('url' => $menu_url !== '' ? $menu_url : home_url('/')),
            );
        }
    }

    return $documents;
}

/**
 * Active campaign menus.
 *
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_site_chat_collect_campaign_documents() {
    if (!function_exists('maca_menulist_get_grouped_campaigns')) {
        return array();
    }

    $documents = array();
    $grouped = maca_menulist_get_grouped_campaigns(
        array(
            'qr_schedule' => false,
            'takeaway_menu' => false,
        )
    );
    $menu_url = maca_menulist_site_chat_find_menu_page_url();

    foreach ($grouped as $group) {
        $campaign = $group['campaign'];
        $campaign_id = (int) $campaign->id;
        $name = maca_menulist_get_campaign_display_name($campaign);
        $lines = array(
            __('Campaign menu:', 'maca-restu-pro') . ' ' . $name,
        );

        $dish_names = array();

        foreach ($group['dishes'] as $dish) {
            $dish_title = isset($dish->title) ? (string) $dish->title : '';

            if (isset($dish->title_en) && (string) $dish->title_en !== '') {
                $dish_title = maca_menulist_get_bilingual_field($dish_title, (string) $dish->title_en);
            }

            if ($dish_title !== '') {
                $dish_names[] = $dish_title;
            }
        }

        if (!empty($dish_names)) {
            $lines[] = __('Included dishes:', 'maca-restu-pro') . ' ' . implode(', ', $dish_names);
        }

        $documents[] = array(
            'chunk_key' => 'campaign:' . $campaign_id,
            'source_type' => 'campaign',
            'source_id' => (string) $campaign_id,
            'title' => $name,
            'content' => implode("\n", $lines),
            'meta' => array('url' => $menu_url !== '' ? $menu_url : home_url('/')),
        );
    }

    return $documents;
}

/**
 * Upcoming public events.
 *
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_site_chat_collect_event_documents() {
    if (!function_exists('maca_menulist_info_hub_get_public_events') || !function_exists('maca_menulist_info_hub_feature_available')) {
        return array();
    }

    if (!maca_menulist_info_hub_feature_available() || !maca_menulist_info_hub_enabled()) {
        return array();
    }

    $documents = array();
    $occurrences = maca_menulist_info_hub_get_public_events(
        array(
            'limit' => 50,
            'offset' => 0,
        )
    );
    $events_page = maca_menulist_site_chat_find_info_hub_page_url('events');

    foreach ($occurrences as $occurrence) {
        $event = isset($occurrence->event) ? $occurrence->event : null;

        if (!$event) {
            continue;
        }

        $event_id = (int) $occurrence->event_id;
        $date = isset($occurrence->occurrence_date) ? (string) $occurrence->occurrence_date : '';
        $chunk_key = 'event:' . $event_id . ':' . str_replace('-', '', $date);
        $title = maca_menulist_info_hub_get_event_title($event);
        $lines = array(
            __('Event:', 'maca-restu-pro') . ' ' . $title,
        );

        if ($date !== '') {
            $lines[] = __('Date:', 'maca-restu-pro') . ' ' . maca_menulist_format_wp_date($date);
        }

        if (!empty($occurrence->time_start)) {
            $time = substr((string) $occurrence->time_start, 0, 5);

            if (!empty($occurrence->time_end)) {
                $time .= '–' . substr((string) $occurrence->time_end, 0, 5);
            }

            $lines[] = __('Time:', 'maca-restu-pro') . ' ' . $time;
        }

        $description = maca_menulist_info_hub_get_event_description($event);

        if ($description !== '') {
            $lines[] = $description;
        }

        $location = maca_menulist_info_hub_get_event_location($event);

        if ($location !== '') {
            $lines[] = __('Location:', 'maca-restu-pro') . ' ' . $location;
        }

        $price = maca_menulist_info_hub_get_event_price_label($event);

        if ($price !== '') {
            $lines[] = __('Price:', 'maca-restu-pro') . ' ' . $price;
        }

        $event_url = $events_page;
        if ($events_page !== '' && function_exists('maca_menulist_info_hub_occurrence_detail_anchor_id')) {
            $event_url = maca_menulist_site_chat_build_page_anchor_url(
                $events_page,
                maca_menulist_info_hub_occurrence_detail_anchor_id($occurrence)
            );
        }

        $documents[] = array(
            'chunk_key' => $chunk_key,
            'source_type' => 'event',
            'source_id' => (string) $event_id,
            'title' => $title,
            'content' => implode("\n", $lines),
            'meta' => array('url' => $event_url !== '' ? $event_url : home_url('/')),
        );
    }

    return $documents;
}

/**
 * Published news posts from Info hub.
 *
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_site_chat_collect_news_documents() {
    if (!function_exists('maca_menulist_info_hub_get_public_news') || !function_exists('maca_menulist_info_hub_feature_available')) {
        return array();
    }

    if (!maca_menulist_info_hub_feature_available() || !maca_menulist_info_hub_enabled()) {
        return array();
    }

    $documents = array();
    $items = maca_menulist_info_hub_get_public_news(
        array(
            'limit' => 30,
            'offset' => 0,
        )
    );
    $news_page = maca_menulist_site_chat_find_info_hub_page_url('news');

    foreach ($items as $news) {
        $news_id = (int) $news->id;
        $title = maca_menulist_info_hub_get_news_title($news);
        $content = maca_menulist_info_hub_get_news_content_plain($news);
        $excerpt = maca_menulist_info_hub_get_news_excerpt($news);

        if ($content === '' && $excerpt !== '') {
            $content = $excerpt;
        }

        if ($content === '') {
            continue;
        }

        $lines = array(
            __('News:', 'maca-restu-pro') . ' ' . $title,
            $content,
        );

        $news_url = maca_menulist_site_chat_build_page_anchor_url($news_page, 'maca-info-news-' . $news_id);

        $documents[] = array(
            'chunk_key' => 'news:' . $news_id,
            'source_type' => 'news',
            'source_id' => (string) $news_id,
            'title' => $title,
            'content' => implode("\n", $lines),
            'meta' => array('url' => $news_url !== '' ? $news_url : home_url('/')),
        );
    }

    return $documents;
}

/**
 * Optional selected WordPress pages.
 *
 * @return array<int, array<string, mixed>>
 */
function maca_menulist_site_chat_collect_wp_page_documents() {
    $page_ids = maca_menulist_site_chat_get_wp_page_ids();

    if (empty($page_ids)) {
        return array();
    }

    $documents = array();

    foreach ($page_ids as $page_id) {
        $post = get_post($page_id);

        if (!$post instanceof WP_Post || $post->post_status !== 'publish' || $post->post_type !== 'page') {
            continue;
        }

        $content = wp_strip_all_tags((string) $post->post_content);
        $content = trim(preg_replace('/\s+/u', ' ', $content));

        if ($content === '') {
            continue;
        }

        $title = get_the_title($post);
        $slug = trim((string) $post->post_name);
        $permalink = get_permalink($post);
        $header_lines = array($title);

        if ($slug !== '') {
            $header_lines[] = __('Page slug:', 'maca-restu-pro') . ' ' . $slug;
        }

        $path = is_string($permalink) ? (string) wp_parse_url($permalink, PHP_URL_PATH) : '';

        if ($path !== '') {
            $header_lines[] = __('Page path:', 'maca-restu-pro') . ' ' . $path;
        }

        $content = implode("\n", $header_lines) . "\n\n" . $content;

        if (function_exists('mb_substr')) {
            $content = mb_substr($content, 0, 4000);
        } else {
            $content = substr($content, 0, 4000);
        }

        $documents[] = array(
            'chunk_key' => 'wp_page:' . $page_id,
            'source_type' => 'wp_page',
            'source_id' => (string) $page_id,
            'title' => $title,
            'content' => $content,
            'meta' => array(
                'url' => is_string($permalink) ? $permalink : '',
                'slug' => $slug,
            ),
        );
    }

    return $documents;
}

/**
 * Build or rebuild the full chat index.
 *
 * @return array{success: bool, message: string, count: int}|WP_Error
 */
function maca_menulist_site_chat_build_index() {
    if (!maca_menulist_site_chat_feature_available()) {
        return new WP_Error('maca_site_chat_locked', __('Site chatbot requires an active Pro subscription.', 'maca-restu-pro'));
    }

    if (!maca_menulist_site_chat_has_api_key()) {
        return new WP_Error('maca_site_chat_no_key', __('OpenAI API key is not configured.', 'maca-restu-pro'));
    }

    $documents = maca_menulist_site_chat_collect_documents();

    if (empty($documents)) {
        maca_menulist_db_site_chat_delete_all_chunks();
        maca_menulist_site_chat_set_index_status(
            array(
                'success' => false,
                'message' => __('No content found to index.', 'maca-restu-pro'),
                'count' => 0,
                'built_at' => gmdate('c'),
            )
        );

        return new WP_Error('maca_site_chat_empty_index', __('No content found to index.', 'maca-restu-pro'));
    }

    maca_menulist_db_site_chat_delete_all_chunks();

    $batch_size = 40;
    $saved = 0;

    foreach (array_chunk($documents, $batch_size) as $batch) {
        $texts = array();

        foreach ($batch as $doc) {
            $texts[] = $doc['content'];
        }

        $vectors = maca_menulist_site_chat_openai_embeddings($texts);

        if (is_wp_error($vectors)) {
            maca_menulist_site_chat_set_index_status(
                array(
                    'success' => false,
                    'message' => $vectors->get_error_message(),
                    'count' => $saved,
                    'built_at' => gmdate('c'),
                )
            );

            return $vectors;
        }

        foreach ($batch as $index => $doc) {
            if (!isset($vectors[ $index ])) {
                continue;
            }

            $doc['embedding'] = wp_json_encode($vectors[ $index ]);

            if (maca_menulist_db_site_chat_upsert_chunk($doc)) {
                ++$saved;
            }
        }
    }

    $message = sprintf(
        /* translators: %d: number of indexed chunks */
        _n('%d chunk indexed.', '%d chunks indexed.', $saved, 'maca-restu-pro'),
        $saved
    );

    maca_menulist_site_chat_set_index_status(
        array(
            'success' => true,
            'message' => $message,
            'count' => $saved,
            'built_at' => gmdate('c'),
        )
    );

    return array(
        'success' => true,
        'message' => $message,
        'count' => $saved,
    );
}

add_action(
    'maca_menulist_site_chat_reindex_event',
    static function () {
        maca_menulist_site_chat_build_index();
    }
);

add_action(
    maca_menulist_site_chat_cron_hook(),
    static function () {
        if (maca_menulist_site_chat_enabled() && maca_menulist_site_chat_has_api_key()) {
            maca_menulist_site_chat_build_index();
        }
    }
);
