<?php

namespace BookWellAB;

defined('ABSPATH') || exit;

if (!class_exists('BookWellAB_Zoom')) {

    /**
     * Free Zoom Server-to-Server OAuth integration.
     */
    class BookWellAB_Zoom
    {
        private static $instance = null;

        /** @var BookWellAB_Database */
        private $bwdb;

        public static function get_instance()
        {
            if (self::$instance === null) {
                self::$instance = new self();
            }
            return self::$instance;
        }

        public function __construct()
        {
            $this->bwdb = new BookWellAB_Database();

            add_filter('bookwellab_settings_defaults', [$this, 'filter_settings_defaults']);
            add_filter('bookwellab_settings_sanitizer_map', [$this, 'filter_settings_sanitizer_map']);
            add_filter('bookwellab_settings_allowed_tabs', [$this, 'filter_settings_allowed_tabs']);
            add_action('bookwellab_settings_extra_tabs', [$this, 'render_integrations_tab']);

            add_action('bookwellab_service_settings_fields', [$this, 'render_service_zoom_field']);
            add_filter('bookwellab_admin_script_vriable_data', [$this, 'filter_admin_script_data'], 20, 2);
            add_filter('bookwellab_page_method_data', [$this, 'filter_page_method_data'], 20, 2);

            add_action('wp_ajax_bookwellab_zoom_list_users', [$this, 'ajax_list_users']);

            add_action('bookwellab_appointment_created', [$this, 'on_appointment_created'], 20, 3);
            add_action('bookwellab_admin_appointment_updated', [$this, 'on_appointment_updated'], 20, 3);
            add_action('bookwellab_appointment_cancelled_by_customer', [$this, 'on_appointment_cancelled'], 20, 2);
            add_action('bookwellab_paypal_appointment_confirmed', [$this, 'on_paypal_confirmed'], 20, 2);

            add_filter('bookwellab_notification_placeholders', [$this, 'filter_notification_placeholders'], 10, 3);
            add_filter('bookwellab_appointments_list_data', [$this, 'filter_appointments_list_data']);
            add_action('bookwellab_appointments_service_staff_column', [$this, 'render_list_zoom_link']);
            add_action('bookwellab_appointments_service_staff_mobile', [$this, 'render_list_zoom_link_mobile']);
        }

        /**
         * @param array $defaults Settings defaults.
         * @return array
         */
        public function filter_settings_defaults($defaults)
        {
            if (!is_array($defaults)) {
                $defaults = [];
            }
            $defaults['zoom'] = [
                'enabled' => 'no',
                'account_id' => '',
                'client_id' => '',
                'client_secret' => '',
                'event_title' => '%service_name% - %customer_first_name% %customer_last_name%',
                /* translators: %staff_name%, %appointment_date%, %appointment_time%: runtime Zoom meeting description placeholders. */
                'event_description' => __('Appointment with %staff_name% on %appointment_date% at %appointment_time%', 'bookwellnow-appointment-booking'),
                'oauth_token' => '',
            ];
            return $defaults;
        }

        /**
         * @param array $map Sanitizer map.
         * @return array
         */
        public function filter_settings_sanitizer_map($map)
        {
            if (!is_array($map)) {
                $map = [];
            }
            $map['zoom.enabled'] = 'yes_no';
            $map['zoom.account_id'] = 'text';
            $map['zoom.client_id'] = 'text';
            $map['zoom.client_secret'] = 'smtp_password';
            $map['zoom.event_title'] = 'text';
            $map['zoom.event_description'] = 'textarea';
            $map['zoom.oauth_token'] = 'text';
            return $map;
        }

        /**
         * @param array $tabs Allowed settings tabs.
         * @return array
         */
        public function filter_settings_allowed_tabs($tabs)
        {
            if (!is_array($tabs)) {
                $tabs = [];
            }
            if (!in_array('integrations', $tabs, true)) {
                $tabs[] = 'integrations';
            }
            return $tabs;
        }

        /**
         * Settings → Integrations → Zoom tab HTML.
         *
         * @return void
         */
        public function render_integrations_tab()
        {
            ?>
            <el-tab-pane name="integrations">
                <template #label>
                    <span class="bw-settings-tab-label">
                        <span class="dashicons dashicons-admin-plugins" aria-hidden="true"></span>
                        <span><?php esc_html_e('Integrations', 'bookwellnow-appointment-booking'); ?></span>
                    </span>
                </template>
                <el-form :model="settings_form" label-position="top">
                    <el-collapse v-model="integrations_settings_expanded" class="bw-settings-collapse bw-zoom-settings-collapse bw-integrations-settings-collapse">
                        <el-collapse-item name="zoom" title="<?php esc_attr_e('Zoom Integration', 'bookwellnow-appointment-booking'); ?>">
                            <p class="bw-helper-text" style="margin-top: 0;">
                                <?php
                                echo esc_html__(
                                    'Connect a Zoom Server-to-Server OAuth app (Account ID, Client ID, Client Secret). Enable Zoom on staff and services to auto-create meetings when appointments are booked.',
                                    'bookwellnow-appointment-booking'
                                );
                                ?>
                                <a href="https://bookwellnow.com/docs/zoom-integration" target="_blank" rel="noopener noreferrer">
                                    <?php esc_html_e('Setup guide', 'bookwellnow-appointment-booking'); ?>
                                </a>
                            </p>

                            <el-row type="flex" align="middle" class="bw-settings-toggle-row" style="margin-bottom: 20px;">
                                <el-col :span="16">
                                    <strong><?php esc_html_e('Enable Zoom Integration', 'bookwellnow-appointment-booking'); ?></strong>
                                </el-col>
                                <el-col :span="8" class="bw-right-align">
                                    <el-switch v-model="settings_form.zoom.enabled" active-value="yes" inactive-value="no"></el-switch>
                                </el-col>
                            </el-row>

                            <div class="bw-zoom-config-note" v-if="settings_form.zoom.enabled === 'yes'">
                                <strong><?php esc_html_e('Note:', 'bookwellnow-appointment-booking'); ?></strong>
                                <?php
                                echo esc_html__(
                                    'After saving credentials here, also configure Zoom on Staff and Services. Edit each staff member → enable Zoom Integration and assign a Zoom User. Then edit each virtual service → enable Zoom Integration. Meetings are created only when Zoom is enabled for both the staff and the service.',
                                    'bookwellnow-appointment-booking'
                                );
                                ?>
                            </div>

                            <template v-if="settings_form.zoom.enabled === 'yes'">
                                <el-row :gutter="20">
                                    <el-col :span="8">
                                        <el-form-item label="<?php esc_attr_e('Account ID', 'bookwellnow-appointment-booking'); ?>">
                                            <el-input v-model="settings_form.zoom.account_id" autocomplete="off"></el-input>
                                        </el-form-item>
                                    </el-col>
                                    <el-col :span="8">
                                        <el-form-item label="<?php esc_attr_e('Client ID', 'bookwellnow-appointment-booking'); ?>">
                                            <el-input v-model="settings_form.zoom.client_id" autocomplete="off"></el-input>
                                        </el-form-item>
                                    </el-col>
                                    <el-col :span="8">
                                        <el-form-item label="<?php esc_attr_e('Client Secret', 'bookwellnow-appointment-booking'); ?>">
                                            <el-input v-model="settings_form.zoom.client_secret" type="password" show-password autocomplete="off"></el-input>
                                        </el-form-item>
                                    </el-col>
                                </el-row>

                                <h4 class="bw-settings-subsection-title"><?php esc_html_e('Event Settings', 'bookwellnow-appointment-booking'); ?></h4>
                                <el-row :gutter="20">
                                    <el-col :span="24">
                                        <el-form-item label="<?php esc_attr_e('Event Title', 'bookwellnow-appointment-booking'); ?>">
                                            <el-input v-model="settings_form.zoom.event_title" maxlength="200" show-word-limit></el-input>
                                        </el-form-item>
                                    </el-col>
                                    <el-col :span="24">
                                        <el-form-item label="<?php esc_attr_e('Event Description', 'bookwellnow-appointment-booking'); ?>">
                                            <el-input
                                                type="textarea"
                                                :rows="4"
                                                v-model="settings_form.zoom.event_description"
                                                maxlength="2000"
                                                show-word-limit>
                                            </el-input>
                                        </el-form-item>
                                    </el-col>
                                </el-row>
                                <p class="bw-helper-text">
                                    <?php esc_html_e('Placeholders:', 'bookwellnow-appointment-booking'); ?>
                                    %service_name%, %staff_name%, %customer_first_name%, %customer_last_name%, %customer_email%, %appointment_date%, %appointment_time%, %company_name%
                                </p>
                            </template>

                            <div class="bw-zoom-scopes-box">
                                <h4 class="bw-settings-subsection-title" style="margin-top: 0;"><?php esc_html_e('Required Zoom Scopes', 'bookwellnow-appointment-booking'); ?></h4>
                                <p class="bw-helper-text" style="margin-top: 0;">
                                    <?php esc_html_e('Add every scope below. Missing scopes will cause “Could not load Zoom users” or meeting creation failures.', 'bookwellnow-appointment-booking'); ?>
                                </p>

                                <div class="bw-zoom-scopes-grid">
                                    <div class="bw-zoom-scopes-group">
                                        <strong><?php esc_html_e('Meeting → View all user meetings', 'bookwellnow-appointment-booking'); ?></strong>
                                        <ul>
                                            <li><?php esc_html_e('View a meeting', 'bookwellnow-appointment-booking'); ?></li>
                                            <li><?php esc_html_e("View a user's meetings", 'bookwellnow-appointment-booking'); ?></li>
                                            <li><?php esc_html_e("View a user's upcoming meetings", 'bookwellnow-appointment-booking'); ?></li>
                                        </ul>
                                    </div>
                                    <div class="bw-zoom-scopes-group">
                                        <strong><?php esc_html_e('Meeting → View and manage all user meetings', 'bookwellnow-appointment-booking'); ?></strong>
                                        <ul>
                                            <li><?php esc_html_e('Update a meeting', 'bookwellnow-appointment-booking'); ?></li>
                                            <li><?php esc_html_e('Delete a meeting', 'bookwellnow-appointment-booking'); ?></li>
                                            <li><?php esc_html_e('Create invite links for a meeting', 'bookwellnow-appointment-booking'); ?></li>
                                            <li><?php esc_html_e('Create a meeting for a user', 'bookwellnow-appointment-booking'); ?></li>
                                        </ul>
                                    </div>
                                    <div class="bw-zoom-scopes-group">
                                        <strong><?php esc_html_e('Users → View all user information', 'bookwellnow-appointment-booking'); ?></strong>
                                        <ul>
                                            <li><?php esc_html_e("View a user's token", 'bookwellnow-appointment-booking'); ?></li>
                                            <li><?php esc_html_e('View a user', 'bookwellnow-appointment-booking'); ?></li>
                                            <li><?php esc_html_e('View users', 'bookwellnow-appointment-booking'); ?></li>
                                        </ul>
                                    </div>
                                </div>
                            </div>
                        </el-collapse-item>
                        <?php
                        /**
                         * Extra integration panels inside Settings → Integrations (collapse items).
                         * Pro add-ons should hook here instead of registering another Integrations tab.
                         */
                        do_action('bookwellab_settings_integrations_panels');
                        ?>
                    </el-collapse>
                </el-form>
            </el-tab-pane>
            <?php
        }

        /**
         * Service drawer Zoom toggle.
         *
         * @return void
         */
        public function render_service_zoom_field()
        {
            ?>
            <div class="bw-form-element" v-if="zoom_integration_enabled">
                <el-form-item>
                    <template #label>
                        <span class="bw-element-label bw-element-label--with-note">
                            <?php esc_html_e('Enable Zoom Integration:', 'bookwellnow-appointment-booking'); ?>
                            <el-tooltip
                                effect="dark"
                                placement="top"
                                popper-class="bw-zoom-note-tooltip"
                                :show-after="100">
                                <template #content>
                                    <span><?php
                                    echo esc_html__(
                                        'Enable this for virtual services. Meetings are created only if Settings → Integrations → Zoom is enabled and the assigned staff also has Zoom Integration enabled with a Zoom User selected.',
                                        'bookwellnow-appointment-booking'
                                    );
                                    ?></span>
                                </template>
                                <span
                                    class="bw-field-note-icon dashicons dashicons-info-outline"
                                    tabindex="0"
                                    role="img"
                                    aria-label="<?php esc_attr_e('Zoom integration note', 'bookwellnow-appointment-booking'); ?>"></span>
                            </el-tooltip>
                        </span>
                    </template>
                    <el-switch v-model="service_form.bw_zoom_enabled" :active-value="1" :inactive-value="0"></el-switch>
                </el-form-item>
            </div>
            <?php
        }

        /**
         * Inject Zoom fields into staff/service Vue data models.
         *
         * @param array  $data Admin script data.
         * @param string $page Admin page slug.
         * @return array
         */
        public function filter_admin_script_data($data, $page)
        {
            if (!is_array($data)) {
                return $data;
            }

            if (!empty($data['staff_form']) && is_array($data['staff_form'])) {
                if (!isset($data['staff_form']['bw_zoom_enabled'])) {
                    $data['staff_form']['bw_zoom_enabled'] = 0;
                }
                if (!isset($data['staff_form']['bw_zoom_user_id'])) {
                    $data['staff_form']['bw_zoom_user_id'] = '';
                }
            }
            if (!empty($data['staff_form_reset']) && is_array($data['staff_form_reset'])) {
                if (!isset($data['staff_form_reset']['bw_zoom_enabled'])) {
                    $data['staff_form_reset']['bw_zoom_enabled'] = 0;
                }
                if (!isset($data['staff_form_reset']['bw_zoom_user_id'])) {
                    $data['staff_form_reset']['bw_zoom_user_id'] = '';
                }
            }
            if (!empty($data['service_form']) && is_array($data['service_form'])) {
                if (!isset($data['service_form']['bw_zoom_enabled'])) {
                    $data['service_form']['bw_zoom_enabled'] = 0;
                }
            }
            if (!empty($data['service_form_reset']) && is_array($data['service_form_reset'])) {
                if (!isset($data['service_form_reset']['bw_zoom_enabled'])) {
                    $data['service_form_reset']['bw_zoom_enabled'] = 0;
                }
            }
            if (!empty($data['appointment_form_reset']) && is_array($data['appointment_form_reset'])) {
                $data['appointment_form_reset']['bw_zoom_meeting_id'] = '';
                $data['appointment_form_reset']['bw_zoom_host_url'] = '';
                $data['appointment_form_reset']['bw_zoom_join_url'] = '';
            }

            $data['zoom_users_list'] = [];
            $data['zoom_users_loader'] = false;

            if ($page === 'settings') {
                $requested_panel = filter_input(INPUT_GET, 'bw_panel', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
                $requested_panel = is_string($requested_panel) ? sanitize_key($requested_panel) : '';
                $integrations_expanded = [];
                if ($requested_panel !== '') {
                    $integrations_expanded[] = $requested_panel;
                }
                /**
                 * Which Integrations collapse panels start expanded.
                 *
                 * @param array  $integrations_expanded Panel names (e.g. zoom, google_calendar).
                 * @param string $requested_panel       Sanitized bw_panel query value.
                 */
                $integrations_expanded = apply_filters(
                    'bookwellab_settings_integrations_expanded',
                    $integrations_expanded,
                    $requested_panel
                );
                if (!is_array($integrations_expanded)) {
                    $integrations_expanded = [];
                }
                $data['integrations_settings_expanded'] = array_values(array_unique(array_filter(array_map('sanitize_key', $integrations_expanded))));
                // Backward-compatible alias for older Pro snippets.
                $data['zoom_settings_expanded'] = $data['integrations_settings_expanded'];
            } else {
                $data['integrations_settings_expanded'] = [];
                $data['zoom_settings_expanded'] = [];
            }
            $data['zoom_integration_enabled'] = $this->is_zoom_globally_enabled();

            // Do not expose cached OAuth token to the browser.
            if (!empty($data['settings_form']['zoom']) && is_array($data['settings_form']['zoom'])) {
                unset($data['settings_form']['zoom']['oauth_token']);
            }

            return $data;
        }

        /**
         * Staff page Vue methods for Zoom users.
         *
         * @param string $methods Existing methods JS.
         * @param string $page    Admin page.
         * @return string
         */
        public function filter_page_method_data($methods, $page)
        {
            if ($page !== 'staff') {
                return $methods;
            }

            $methods = rtrim((string) $methods);
            if ($methods !== '' && substr($methods, -1) !== ',') {
                $methods .= ',';
            }

            $methods .= '
                bwab_onStaffZoomToggle(value) {
                    const vuedata = this;
                    if (parseInt(value, 10) === 1) {
                        vuedata.bwab_loadZoomUsers();
                    } else {
                        vuedata.staff_form.bw_zoom_user_id = "";
                    }
                },
                bwab_loadZoomUsers() {
                    const vuedata = this;
                    if (vuedata.zoom_users_loader) {
                        return;
                    }
                    vuedata.zoom_users_loader = true;
                    axios.post(bookwellab_ajax_obj.ajax_url, Qs.stringify({
                        action: "bookwellab_zoom_list_users",
                        _wpnonce: bookwellab_ajax_obj.bookwellab_nonce
                    })).then(function(response) {
                        vuedata.zoom_users_loader = false;
                        if (response.data && response.data.success && response.data.data && response.data.data.users) {
                            vuedata.zoom_users_list = response.data.data.users;
                        } else {
                            vuedata.zoom_users_list = [];
                            const msg = (response.data && response.data.data && response.data.data.msg)
                                ? response.data.data.msg
                                : "' . esc_js(__('Could not load Zoom users.', 'bookwellnow-appointment-booking')) . '";
                            vuedata.$notify({ title: "' . esc_js(__('Zoom', 'bookwellnow-appointment-booking')) . '", message: msg, type: "error", duration: 6000 });
                        }
                    }).catch(function() {
                        vuedata.zoom_users_loader = false;
                        vuedata.zoom_users_list = [];
                        vuedata.$notify({
                            title: "' . esc_js(__('Zoom', 'bookwellnow-appointment-booking')) . '",
                            message: "' . esc_js(__('Could not load Zoom users. Network or server error.', 'bookwellnow-appointment-booking')) . '",
                            type: "error",
                            duration: 6000
                        });
                    });
                },
            ';

            return $methods;
        }

        /**
         * AJAX: list Zoom users for staff dropdown.
         *
         * @return void
         */
        public function ajax_list_users()
        {
            if (!BookWellAB_Permissions::has_permission('bookwellab_manage_staff')
                && !BookWellAB_Permissions::has_permission('bookwellab_manage_settings')) {
                wp_send_json_error(['msg' => esc_html__('Unauthorized', 'bookwellnow-appointment-booking')]);
            }
            if (!check_ajax_referer('bw_wp_nonce', '_wpnonce', false)) {
                wp_send_json_error(['msg' => esc_html__('Security token mismatch.', 'bookwellnow-appointment-booking')]);
            }

            if (!$this->is_zoom_globally_enabled()) {
                wp_send_json_error([
                    'msg' => esc_html__('Enable Zoom under Settings → Integrations and save credentials first.', 'bookwellnow-appointment-booking'),
                ]);
            }

            $users = $this->list_zoom_users();
            if (is_wp_error($users)) {
                wp_send_json_error(['msg' => $users->get_error_message()]);
            }

            wp_send_json_success(['users' => $users]);
        }

        /**
         * @param int   $appointment_id Appointment ID.
         * @param array $booking_data   Booking payload.
         * @param array $options        Create options.
         * @return void
         */
        public function on_appointment_created($appointment_id, $booking_data = [], $options = [])
        {
            $this->maybe_create_meeting((int) $appointment_id);
        }

        /**
         * @param int   $appointment_id Appointment ID.
         * @param array $booking_data   Updated fields.
         * @param array $appointment    Appointment row.
         * @return void
         */
        public function on_appointment_updated($appointment_id, $booking_data = [], $appointment = [])
        {
            $status = isset($appointment['bw_status']) ? (string) $appointment['bw_status'] : '';
            if (in_array($status, ['cancelled', 'canceled'], true)) {
                $this->delete_meeting_for_appointment((int) $appointment_id);
                return;
            }
            $this->maybe_create_meeting((int) $appointment_id);
        }

        /**
         * @param int   $appointment_id Appointment ID.
         * @param array $appointment    Appointment row.
         * @return void
         */
        public function on_appointment_cancelled($appointment_id, $appointment = [])
        {
            $this->delete_meeting_for_appointment((int) $appointment_id);
        }

        /**
         * After PayPal confirms and status is set.
         *
         * @param int   $appointment_id Appointment ID.
         * @param array $appointment    Appointment row.
         * @return void
         */
        public function on_paypal_confirmed($appointment_id, $appointment = [])
        {
            $this->maybe_create_meeting((int) $appointment_id);
        }

        /**
         * @param array  $placeholders Placeholders.
         * @param string $trigger      Notification trigger.
         * @param array  $appointment  Appointment data.
         * @return array
         */
        public function filter_notification_placeholders($placeholders, $trigger, $appointment)
        {
            if (!is_array($placeholders)) {
                $placeholders = [];
            }
            $id = isset($appointment['bw_appointment_id']) ? (int) $appointment['bw_appointment_id'] : 0;
            $join = '';
            $host = '';
            if ($id > 0) {
                $row = $this->get_appointment_zoom_row($id);
                if ($row) {
                    $join = (string) ($row['bw_zoom_join_url'] ?? '');
                    $host = (string) ($row['bw_zoom_host_url'] ?? '');
                }
            } else {
                $join = (string) ($appointment['bw_zoom_join_url'] ?? '');
                $host = (string) ($appointment['bw_zoom_host_url'] ?? '');
            }
            $placeholders['%zoom_join_url%'] = $join;
            $placeholders['%zoom_host_url%'] = $host;
            return $placeholders;
        }

        /**
         * @param array $list Appointments list rows.
         * @return array
         */
        public function filter_appointments_list_data($list)
        {
            if (!is_array($list)) {
                return $list;
            }
            foreach ($list as &$row) {
                $row['bw_zoom_join_url'] = isset($row['bw_zoom_join_url']) ? (string) $row['bw_zoom_join_url'] : '';
                $row['bw_zoom_host_url'] = isset($row['bw_zoom_host_url']) ? (string) $row['bw_zoom_host_url'] : '';
                $row['bw_show_zoom'] = (!empty($row['bw_zoom_host_url']) || !empty($row['bw_zoom_join_url']))
                    && isset($row['bw_status'])
                    && $row['bw_status'] === 'approved';
            }
            unset($row);
            return $list;
        }

        /**
         * Admin appointment drawer Zoom link (uses appointment_form when present).
         *
         * @return void
         */
        public function render_admin_zoom_action()
        {
            ?>
            <el-button
                v-if="appointment_form && appointment_form.bw_zoom_host_url && appointment_form.bw_status === 'approved'"
                type="primary"
                link
                tag="a"
                :href="appointment_form.bw_zoom_host_url"
                target="_blank"
                rel="noopener noreferrer"
                style="margin-top: 8px;">
                <?php esc_html_e('Start Zoom Meeting', 'bookwellnow-appointment-booking'); ?>
            </el-button>
            <?php
        }

        /**
         * Appointments list desktop Zoom host link.
         *
         * @return void
         */
        public function render_list_zoom_link()
        {
            ?>
            <div v-if="scope.row.bw_show_zoom && scope.row.bw_zoom_host_url" class="bw-zoom-meeting-link-wrap">
                <el-tooltip
                    effect="dark"
                    placement="top"
                    :content="'<?php echo esc_js(__('Start Zoom Meeting', 'bookwellnow-appointment-booking')); ?>'"
                    :show-after="100">
                    <a
                        :href="scope.row.bw_zoom_host_url"
                        target="_blank"
                        rel="noopener noreferrer"
                        class="bw-zoom-meeting-icon-link"
                        :aria-label="'<?php echo esc_js(__('Start Zoom Meeting', 'bookwellnow-appointment-booking')); ?>'">
                        <svg class="bw-zoom-meeting-icon" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" focusable="false">
                            <path fill="currentColor" d="M17 10.5V7a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-3.5l3.45 2.59c.48.36 1.17.02 1.17-.58V8.49c0-.6-.69-.94-1.17-.58L17 10.5z"/>
                        </svg>
                    </a>
                </el-tooltip>
            </div>
            <?php
        }

        /**
         * Appointments list mobile Zoom host link.
         *
         * @return void
         */
        public function render_list_zoom_link_mobile()
        {
            ?>
            <div v-if="row.bw_show_zoom && row.bw_zoom_host_url" class="bw-appt-mobile-meta bw-zoom-meeting-link-wrap">
                <el-tooltip
                    effect="dark"
                    placement="top"
                    :content="'<?php echo esc_js(__('Start Zoom Meeting', 'bookwellnow-appointment-booking')); ?>'"
                    :show-after="100">
                    <a
                        :href="row.bw_zoom_host_url"
                        target="_blank"
                        rel="noopener noreferrer"
                        class="bw-zoom-meeting-icon-link"
                        :aria-label="'<?php echo esc_js(__('Start Zoom Meeting', 'bookwellnow-appointment-booking')); ?>'">
                        <svg class="bw-zoom-meeting-icon" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" focusable="false">
                            <path fill="currentColor" d="M17 10.5V7a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-3.5l3.45 2.59c.48.36 1.17.02 1.17-.58V8.49c0-.6-.69-.94-1.17-.58L17 10.5z"/>
                        </svg>
                    </a>
                </el-tooltip>
            </div>
            <?php
        }

        /**
         * Create Zoom meeting when gates pass.
         *
         * @param int $appointment_id Appointment ID.
         * @return bool
         */
        public function maybe_create_meeting($appointment_id)
        {
            $appointment_id = (int) $appointment_id;
            if ($appointment_id <= 0 || !$this->is_zoom_globally_enabled()) {
                return false;
            }

            $appointment = $this->get_appointment_row($appointment_id);
            if (!$appointment) {
                return false;
            }

            $status = (string) ($appointment['bw_status'] ?? '');
            if (in_array($status, ['cancelled', 'canceled'], true)) {
                return false;
            }

            // Already has a meeting.
            if (!empty($appointment['bw_zoom_meeting_id']) && !empty($appointment['bw_zoom_join_url'])) {
                return true;
            }

            $service_id = (int) ($appointment['bw_service_id'] ?? 0);
            $staff_id = (int) ($appointment['bw_staff_id'] ?? 0);
            if ($service_id <= 0 || $staff_id <= 0) {
                return false;
            }

            $service = $this->bwdb->select(
                'row',
                '*',
                $this->bwdb->get_table_name('services'),
                'bw_service_id = %d',
                [$service_id]
            );
            $staff = $this->bwdb->select(
                'row',
                '*',
                $this->bwdb->get_table_name('staffs'),
                'bw_staff_id = %d',
                [$staff_id]
            );

            if (empty($service) || empty($staff)) {
                return false;
            }
            if (empty($service['bw_zoom_enabled']) || (int) $service['bw_zoom_enabled'] !== 1) {
                return false;
            }
            if (empty($staff['bw_zoom_enabled']) || (int) $staff['bw_zoom_enabled'] !== 1) {
                return false;
            }

            $zoom_user_id = trim((string) ($staff['bw_zoom_user_id'] ?? ''));
            if ($zoom_user_id === '') {
                return false;
            }

            $token = $this->get_access_token();
            if ($token === '') {
                return false;
            }

            $settings = BookWellAB_Settings::get_settings();
            $zoom = isset($settings['zoom']) && is_array($settings['zoom']) ? $settings['zoom'] : [];
            $title = $this->replace_zoom_placeholders(
                (string) ($zoom['event_title'] ?? '%service_name%'),
                $appointment
            );
            $description = $this->replace_zoom_placeholders(
                (string) ($zoom['event_description'] ?? ''),
                $appointment
            );

            $duration = max(1, (int) ($appointment['bw_duration'] ?? 30));
            $date = (string) ($appointment['bw_date'] ?? '');
            $time = (string) ($appointment['bw_time'] ?? '00:00:00');
            $appointment_ts = strtotime($date . ' ' . $time);
            if ($appointment_ts === false) {
                $appointment_ts = time();
            }
            $start = wp_date('Y-m-d', $appointment_ts) . 'T' . wp_date('H:i:s', $appointment_ts);

            $topic = wp_strip_all_tags($title);
            $agenda = wp_strip_all_tags($description);
            if (function_exists('mb_substr')) {
                $topic = mb_substr($topic, 0, 200);
                $agenda = mb_substr($agenda, 0, 2000);
            } else {
                $topic = substr($topic, 0, 200);
                $agenda = substr($agenda, 0, 2000);
            }

            $body = [
                'topic' => $topic,
                'agenda' => $agenda,
                'start_time' => $start,
                'timezone' => wp_timezone_string(),
                'type' => 2,
                'duration' => $duration,
            ];

            $url = 'https://api.zoom.us/v2/users/' . rawurlencode($zoom_user_id) . '/meetings';
            $response = wp_remote_post(
                $url,
                [
                    'timeout' => 45,
                    'headers' => [
                        'Authorization' => 'Bearer ' . $token,
                        'Content-Type' => 'application/json',
                    ],
                    'body' => wp_json_encode($body),
                ]
            );

            if (is_wp_error($response)) {
                return false;
            }
            $code = (int) wp_remote_retrieve_response_code($response);
            $data = json_decode((string) wp_remote_retrieve_body($response), true);
            if ($code < 200 || $code >= 300 || empty($data['id'])) {
                return false;
            }

            $this->bwdb->upsert(
                $this->bwdb->get_table_name('appointments'),
                [
                    'bw_zoom_meeting_id' => (string) $data['id'],
                    'bw_zoom_host_url' => isset($data['start_url']) ? esc_url_raw((string) $data['start_url']) : '',
                    'bw_zoom_join_url' => isset($data['join_url']) ? esc_url_raw((string) $data['join_url']) : '',
                ],
                ['bw_appointment_id' => $appointment_id]
            );

            return true;
        }

        /**
         * Delete Zoom meeting for appointment and clear columns.
         *
         * @param int $appointment_id Appointment ID.
         * @return void
         */
        public function delete_meeting_for_appointment($appointment_id)
        {
            $appointment_id = (int) $appointment_id;
            $row = $this->get_appointment_zoom_row($appointment_id);
            if (!$row || empty($row['bw_zoom_meeting_id'])) {
                return;
            }

            $meeting_id = (string) $row['bw_zoom_meeting_id'];
            $token = $this->get_access_token();
            if ($token !== '') {
                wp_remote_request(
                    'https://api.zoom.us/v2/meetings/' . rawurlencode($meeting_id),
                    [
                        'method' => 'DELETE',
                        'timeout' => 30,
                        'headers' => [
                            'Authorization' => 'Bearer ' . $token,
                        ],
                    ]
                );
            }

            $this->bwdb->upsert(
                $this->bwdb->get_table_name('appointments'),
                [
                    'bw_zoom_meeting_id' => '',
                    'bw_zoom_host_url' => '',
                    'bw_zoom_join_url' => '',
                ],
                ['bw_appointment_id' => $appointment_id]
            );
        }

        /**
         * @return bool
         */
        public function is_zoom_globally_enabled()
        {
            $settings = BookWellAB_Settings::get_settings();
            return isset($settings['zoom']['enabled']) && $settings['zoom']['enabled'] === 'yes';
        }

        /**
         * @return array<int, array{id: string, email: string, name: string}>|\WP_Error
         */
        public function list_zoom_users()
        {
            if (!$this->is_zoom_globally_enabled()) {
                return new \WP_Error(
                    'zoom_disabled',
                    esc_html__('Enable Zoom under Settings → Integrations and save credentials first.', 'bookwellnow-appointment-booking')
                );
            }

            $token = $this->get_access_token(true);
            if (is_wp_error($token)) {
                return $token;
            }
            if ($token === '') {
                return new \WP_Error(
                    'zoom_token_empty',
                    esc_html__('Could not get Zoom access token. Check Account ID, Client ID, and Client Secret.', 'bookwellnow-appointment-booking')
                );
            }

            // Same endpoint style as (no status filter).
            $response = wp_remote_get(
                'https://api.zoom.us/v2/users?page_size=300',
                [
                    'timeout' => 45,
                    'headers' => [
                        'Authorization' => 'Bearer ' . $token,
                        'Content-Type' => 'application/json',
                    ],
                ]
            );
            if (is_wp_error($response)) {
                return new \WP_Error(
                    'zoom_users_request',
                    sprintf(
                        /* translators: %s: error message */
                        esc_html__('Zoom users request failed: %s', 'bookwellnow-appointment-booking'),
                        $response->get_error_message()
                    )
                );
            }

            $code = (int) wp_remote_retrieve_response_code($response);
            $body_raw = (string) wp_remote_retrieve_body($response);
            $data = json_decode($body_raw, true);

            if ($code !== 200) {
                $api_msg = '';
                if (is_array($data)) {
                    if (!empty($data['message'])) {
                        $api_msg = (string) $data['message'];
                    } elseif (!empty($data['error_description'])) {
                        $api_msg = (string) $data['error_description'];
                    } elseif (!empty($data['reason'])) {
                        $api_msg = (string) $data['reason'];
                    }
                }
                if ($api_msg === '') {
                    $api_msg = sprintf(
                        /* translators: %d: HTTP status */
                        esc_html__('HTTP %d', 'bookwellnow-appointment-booking'),
                        $code
                    );
                }

                return new \WP_Error(
                    'zoom_users_http',
                    sprintf(
                        /* translators: %s: Zoom API error */
                        esc_html__('Could not load Zoom users: %s. Confirm User scopes (user:read:user:admin / view users) and that the app is activated.', 'bookwellnow-appointment-booking'),
                        $api_msg
                    )
                );
            }

            if (empty($data['users']) || !is_array($data['users'])) {
                return [];
            }

            $out = [];
            foreach ($data['users'] as $user) {
                $id = isset($user['id']) ? (string) $user['id'] : '';
                if ($id === '') {
                    continue;
                }
                $email = isset($user['email']) ? (string) $user['email'] : '';
                $name = trim(
                    (isset($user['first_name']) ? (string) $user['first_name'] : '')
                    . ' '
                    . (isset($user['last_name']) ? (string) $user['last_name'] : '')
                );
                if ($name === '') {
                    $name = $email !== '' ? $email : $id;
                }
                $out[] = [
                    'id' => $id,
                    'email' => $email,
                    'name' => $name . ($email !== '' ? ' (' . $email . ')' : ''),
                ];
            }
            return $out;
        }

        /**
         * Server-to-Server OAuth access token.
         *
         * @param bool $return_error When true, return WP_Error on failure instead of empty string.
         * @return string|\WP_Error
         */
        public function get_access_token($return_error = false)
        {
            $settings = BookWellAB_Settings::get_settings();
            $zoom = isset($settings['zoom']) && is_array($settings['zoom']) ? $settings['zoom'] : [];

            $cached = $this->normalize_oauth_token_cache($zoom['oauth_token'] ?? null);
            if (is_array($cached)
                && !empty($cached['access_token'])
                && !empty($cached['expires_in'])
                && (int) $cached['expires_in'] > (time() + 60)
            ) {
                return (string) $cached['access_token'];
            }

            $account_id = trim((string) ($zoom['account_id'] ?? ''));
            $client_id = trim((string) ($zoom['client_id'] ?? ''));
            $client_secret = trim((string) ($zoom['client_secret'] ?? ''));
            if ($account_id === '' || $client_id === '' || $client_secret === '') {
                return $return_error
                    ? new \WP_Error(
                        'zoom_missing_creds',
                        esc_html__('Zoom Account ID, Client ID, and Client Secret are required in Settings → Integrations.', 'bookwellnow-appointment-booking')
                    )
                    : '';
            }

            $response = wp_remote_post(
                'https://zoom.us/oauth/token',
                [
                    'timeout' => 45,
                    'headers' => [
                        'Authorization' => 'Basic ' . base64_encode($client_id . ':' . $client_secret),
                    ],
                    'body' => [
                        'grant_type' => 'account_credentials',
                        'account_id' => $account_id,
                    ],
                ]
            );

            if (is_wp_error($response)) {
                return $return_error
                    ? new \WP_Error(
                        'zoom_token_request',
                        sprintf(
                            /* translators: %s: error message */
                            esc_html__('Zoom token request failed: %s', 'bookwellnow-appointment-booking'),
                            $response->get_error_message()
                        )
                    )
                    : '';
            }

            $code = (int) wp_remote_retrieve_response_code($response);
            $data = json_decode((string) wp_remote_retrieve_body($response), true);
            if ($code !== 200 || empty($data['access_token'])) {
                $api_msg = '';
                if (is_array($data)) {
                    if (!empty($data['reason'])) {
                        $api_msg = (string) $data['reason'];
                    } elseif (!empty($data['error_description'])) {
                        $api_msg = (string) $data['error_description'];
                    } elseif (!empty($data['error'])) {
                        $api_msg = (string) $data['error'];
                    } elseif (!empty($data['message'])) {
                        $api_msg = (string) $data['message'];
                    }
                }
                if ($api_msg === '') {
                    $api_msg = sprintf(
                        /* translators: %d: HTTP status */
                        esc_html__('HTTP %d', 'bookwellnow-appointment-booking'),
                        $code
                    );
                }

                return $return_error
                    ? new \WP_Error(
                        'zoom_token_http',
                        sprintf(
                            /* translators: %s: Zoom API error */
                            esc_html__('Zoom authentication failed: %s. Recheck Account ID / Client ID / Client Secret and activate the Server-to-Server app.', 'bookwellnow-appointment-booking'),
                            $api_msg
                        )
                    )
                    : '';
            }

            $expires_in = isset($data['expires_in']) ? (int) $data['expires_in'] : 3600;
            $store = [
                'access_token' => (string) $data['access_token'],
                'expires_in' => time() + $expires_in,
                'token_type' => isset($data['token_type']) ? (string) $data['token_type'] : 'bearer',
            ];

            $this->bwdb->update_settings_by_type(
                'zoom',
                [
                    'oauth_token' => $store,
                ]
            );

            return (string) $data['access_token'];
        }

        /**
         * Settings DB may auto-decode JSON, so oauth_token can be array or string.
         *
         * @param mixed $raw Raw setting value.
         * @return array<string, mixed>
         */
        private function normalize_oauth_token_cache($raw)
        {
            if (is_array($raw)) {
                return $raw;
            }
            if (!is_string($raw) || $raw === '') {
                return [];
            }
            $decoded = json_decode($raw, true);
            return is_array($decoded) ? $decoded : [];
        }

        /**
         * @param int $appointment_id Appointment ID.
         * @return array|null
         */
        private function get_appointment_row($appointment_id)
        {
            return $this->bwdb->select(
                'row',
                '*',
                $this->bwdb->get_table_name('appointments'),
                'bw_appointment_id = %d',
                [(int) $appointment_id]
            ) ?: null;
        }

        /**
         * @param int $appointment_id Appointment ID.
         * @return array|null
         */
        private function get_appointment_zoom_row($appointment_id)
        {
            return $this->bwdb->select(
                'row',
                'bw_zoom_meeting_id, bw_zoom_host_url, bw_zoom_join_url',
                $this->bwdb->get_table_name('appointments'),
                'bw_appointment_id = %d',
                [(int) $appointment_id]
            ) ?: null;
        }

        /**
         * @param string $text        Template.
         * @param array  $appointment Appointment row.
         * @return string
         */
        private function replace_zoom_placeholders($text, $appointment)
        {
            $customer_name = (string) ($appointment['bw_customer_name'] ?? '');
            $parts = preg_split('/\s+/', trim($customer_name), 2);
            $first = $parts[0] ?? '';
            $last = $parts[1] ?? '';

            $settings = BookWellAB_Settings::get_settings();
            $company = isset($settings['general']['company_name'])
                ? (string) $settings['general']['company_name']
                : get_bloginfo('name');

            $map = [
                '%service_name%' => (string) ($appointment['bw_service_name'] ?? ''),
                '%staff_name%' => (string) ($appointment['bw_staff_name'] ?? ''),
                '%customer_first_name%' => $first,
                '%customer_last_name%' => $last,
                '%customer_email%' => (string) ($appointment['bw_customer_email'] ?? ''),
                '%customer_phone%' => (string) ($appointment['bw_customer_phone'] ?? ''),
                '%appointment_date%' => (string) ($appointment['bw_date'] ?? ''),
                '%appointment_time%' => (string) ($appointment['bw_time'] ?? ''),
                '%appointment_price%' => (string) ($appointment['bw_price'] ?? ''),
                '%company_name%' => $company,
            ];

            return str_replace(array_keys($map), array_values($map), (string) $text);
        }
    }
}
