<?php
namespace Bookaro\Controller;

defined( 'ABSPATH' ) || exit;

/**
 * Registers the Bookaro service catalog post type for generic mode.
 */
class ServicePostTypeController
{
    public function register_hooks(): void
    {
        if ( ! $this->generic_mode_enabled() ) {
            return;
        }
        add_action( 'init', [ $this, 'register_post_type' ] );
        add_action( 'init', [ $this, 'register_meta' ] );
        add_action( 'add_meta_boxes', [ $this, 'register_meta_box' ] );
        add_action( 'save_post_' . BOOKARO_SERVICE_POST_TYPE, [ $this, 'save_meta' ] );
        add_action( 'load-post-new.php', [ $this, 'maybe_block_new_service' ] );
        // Grant the bookaro_service custom CPT capabilities to any user who
        // already holds `manage_options`. We do this via user_has_cap rather
        // than mapping every CPT primitive directly to `manage_options` in the
        // register_post_type() capabilities array — that older pattern silently
        // poisons WordPress's $post_type_meta_caps global so that any later
        // current_user_can( 'manage_options' ) check (without a post arg)
        // recurses into the per-post `delete_post` meta cap, which short
        // circuits to `do_not_allow` and locks admins out of unrelated screens
        // like Porto's Speed Optimize Wizard. See WP core
        // wp-includes/post.php::_post_type_meta_capabilities() / map_meta_cap().
        add_filter( 'user_has_cap', [ $this, 'grant_service_caps_to_admins' ], 10, 4 );
        // Design alignment: the Services CPT screens are rendered by WP core
        // and otherwise look like a plain post list, visually disconnected
        // from the rest of the plugin's branded admin pages (which render
        // inside `.bookaro-admin` and load admin-settings.css). Load that same
        // styling here and render the shared Bookaro hero atop the list so the
        // Services screen matches the Bookings / Settings pages.
        add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_assets' ] );
        add_action( 'all_admin_notices', [ $this, 'render_admin_branding' ] );
        // Surface Price + Duration on the Services list table. WP's default
        // CPT list shows only Title + Date, so an admin can't see what each
        // service costs / how long it runs without opening it.
        add_filter( 'manage_' . BOOKARO_SERVICE_POST_TYPE . '_posts_columns', [ $this, 'service_list_columns' ] );
        add_action( 'manage_' . BOOKARO_SERVICE_POST_TYPE . '_posts_custom_column', [ $this, 'render_service_list_column' ], 10, 2 );
    }

    /**
     * Grant bookaro_service CPT custom primitive caps to administrators.
     *
     * @param array<string,bool> $allcaps Existing all-caps for the user.
     * @param array<int,string>  $caps    Required caps for the current check.
     * @param array<int,mixed>   $args    Original cap-check args.
     * @param \WP_User           $user    The user being checked.
     * @return array<string,bool>
     */
    public function grant_service_caps_to_admins( $allcaps, $caps, $args, $user ) {
        unset( $caps, $args, $user );
        if ( empty( $allcaps['manage_options'] ) ) {
            return $allcaps;
        }
        foreach ( [
            'edit_bookaro_service',
            'read_bookaro_service',
            'delete_bookaro_service',
            'edit_bookaro_services',
            'edit_others_bookaro_services',
            'publish_bookaro_services',
            'read_private_bookaro_services',
            'delete_bookaro_services',
            'delete_private_bookaro_services',
            'delete_published_bookaro_services',
            'delete_others_bookaro_services',
            'edit_private_bookaro_services',
            'edit_published_bookaro_services',
            'create_bookaro_services',
        ] as $cap ) {
            $allcaps[ $cap ] = true;
        }
        return $allcaps;
    }

    public function maybe_block_new_service(): void
    {
        if ( ! $this->generic_mode_enabled() ) {
            return;
        }
        if ( ! function_exists( 'get_current_screen' ) ) {
            return;
        }
        $screen = get_current_screen();
        if ( ! $screen || BOOKARO_SERVICE_POST_TYPE !== ( $screen->post_type ?? '' ) ) {
            return;
        }
        if ( ! function_exists( 'bookaro_service_limit_reached' ) || ! bookaro_service_limit_reached() ) {
            return;
        }

        wp_die(
            esc_html__( 'Service limit reached for this site.', 'mybookaro' ),
            esc_html__( 'Service limit reached', 'mybookaro' ),
            [ 'response' => 403 ]
        );
    }

    /**
     * Is the current admin screen a Services CPT screen (list or editor)?
     */
    private function is_service_admin_screen(): bool
    {
        if ( ! function_exists( 'get_current_screen' ) ) {
            return false;
        }
        $screen = get_current_screen();
        if ( ! $screen ) {
            return false;
        }
        return BOOKARO_SERVICE_POST_TYPE === ( $screen->post_type ?? '' )
            && in_array( ( $screen->base ?? '' ), [ 'edit', 'post' ], true );
    }

    /**
     * Is the current admin screen the Services CPT list table?
     */
    private function is_service_list_screen(): bool
    {
        if ( ! function_exists( 'get_current_screen' ) ) {
            return false;
        }
        $screen = get_current_screen();
        return $screen
            && BOOKARO_SERVICE_POST_TYPE === ( $screen->post_type ?? '' )
            && 'edit' === ( $screen->base ?? '' );
    }

    /**
     * Load the shared Bookaro admin stylesheet + CSS-variable theme on the
     * Services CPT screens so the branded hero (and any Bookaro components)
     * render with the same colours as the rest of the admin suite.
     */
    public function enqueue_admin_assets(): void
    {
        if ( ! $this->generic_mode_enabled() || ! $this->is_service_admin_screen() ) {
            return;
        }
        wp_enqueue_style(
            'bookaro-admin-settings',
            BOOKARO_PLUGIN_URL . 'assets/css/admin-settings.css',
            [],
            BOOKARO_VERSION
        );
        wp_add_inline_style( 'bookaro-admin-settings', $this->build_admin_theme_css() );

        // Service metabox behavior: disable the per-listing selectors when the
        // "shared / global service" checkbox is on. Attached as inline JS on a
        // dedicated, src-less admin script handle instead of an inline script
        // element inside the metabox markup.
        $handle = 'bookaro-service-meta-box';
        if ( ! wp_script_is( $handle, 'registered' ) ) {
            wp_register_script( $handle, false, [], BOOKARO_VERSION, true );
        }
        wp_enqueue_script( $handle );
        wp_add_inline_script(
            $handle,
            '(function(){'
            . "var shared=document.getElementById('bookaro-service-shared');"
            . "var listing=document.getElementById('bookaro-service-listing');"
            . "var listings=document.getElementById('bookaro-service-listings');"
            . 'if(!shared||(!listing&&!listings)){return;}'
            . 'function toggleListing(){'
            . 'if(listing){listing.disabled=shared.checked;}'
            . 'if(listings){listings.disabled=shared.checked;}'
            . '}'
            . "shared.addEventListener('change',toggleListing);"
            . 'toggleListing();'
            . '})();'
        );
    }

    /**
     * Build the `.bookaro-admin` CSS-variable theme. admin-settings.css uses
     * `var(--bookaro-*)` with no built-in fallbacks, so the variables must be
     * injected (mirrors what the Settings / Setup Wizard pages do). Honours
     * the same `bookaro_admin_settings_theme` filter for colour consistency.
     */
    private function build_admin_theme_css(): string
    {
        $defaults = [
            'accent'        => '#0f766e',
            'accent_soft'   => '#ccfbf1',
            'accent_text'   => '#134e4a',
            'surface'       => '#ffffff',
            'surface_alt'   => '#f8fafc',
            'surface_muted' => '#f1f5f9',
            'border'        => '#e2e8f0',
            'text'          => '#0f172a',
            'muted'         => '#64748b',
            'danger'        => '#dc2626',
            'warning'       => '#f59e0b',
            'success'       => '#16a34a',
            'shadow'        => 'rgba(15, 23, 42, 0.08)',
        ];
        $theme = apply_filters( 'bookaro_admin_settings_theme', $defaults );
        if ( ! is_array( $theme ) ) {
            $theme = $defaults;
        }
        $css = '.bookaro-admin{';
        foreach ( $defaults as $key => $fallback ) {
            $value = (string) ( $theme[ $key ] ?? $fallback );
            // Permit only safe CSS colour tokens (hex / rgb(a) / hsl / named).
            $value = preg_replace( '/[^#a-zA-Z0-9.,()%\s-]/', '', $value );
            if ( '' === trim( $value ) ) {
                $value = $fallback;
            }
            $css .= '--bookaro-' . str_replace( '_', '-', $key ) . ':' . $value . ';';
        }
        $css .= '}';
        // The injected hero is inside .wrap (via all_admin_notices); give it
        // breathing room above the list table.
        $css .= '.bookaro-admin-services{margin:8px 0 16px;}';
        if ( $this->is_service_list_screen() ) {
            // The hero now carries the page title + actions, so hide WP's
            // default heading + "Add New" button to avoid a duplicated header.
            $css .= 'body.post-type-' . BOOKARO_SERVICE_POST_TYPE . ' .wrap > h1.wp-heading-inline,';
            $css .= 'body.post-type-' . BOOKARO_SERVICE_POST_TYPE . ' .wrap > a.page-title-action{display:none;}';
        }
        return $css;
    }

    /**
     * Render the shared Bookaro hero atop the Services list screen so it
     * matches the Bookings / Settings pages. Hooked to all_admin_notices,
     * which fires on every admin screen, so this self-scopes to the list.
     */
    public function render_admin_branding(): void
    {
        if ( ! $this->generic_mode_enabled() || ! $this->is_service_list_screen() ) {
            return;
        }
        $add_url      = admin_url( 'post-new.php?post_type=' . BOOKARO_SERVICE_POST_TYPE );
        $settings_url = admin_url( 'admin.php?page=bookaro-booking-settings&tab=general' );
        $logo         = BOOKARO_PLUGIN_URL . 'assets/img/mb-logo.svg';
        ?>
        <div class="bookaro-admin bookaro-admin-services">
            <div class="bookaro-card bookaro-hero bookaro-bookings-hero">
                <div class="bookaro-hero__content">
                    <div class="bookaro-hero__brand">
                        <img src="<?php echo esc_url( $logo ); ?>" alt="<?php esc_attr_e( 'MyBookaro', 'mybookaro' ); ?>" width="120" height="36" />
                    </div>
                    <h1><?php esc_html_e( 'Services', 'mybookaro' ); ?></h1>
                    <p class="description"><?php esc_html_e( 'Manage the services customers can book — set a price and duration for each.', 'mybookaro' ); ?></p>
                </div>
                <div class="bookaro-hero__actions">
                    <a class="button button-primary" href="<?php echo esc_url( $add_url ); ?>"><?php esc_html_e( 'Add Service', 'mybookaro' ); ?></a>
                    <a class="button button-secondary" href="<?php echo esc_url( $settings_url ); ?>"><?php esc_html_e( 'Open settings', 'mybookaro' ); ?></a>
                </div>
            </div>
        </div>
        <?php
    }

    /**
     * Add Price + Duration columns to the Services list table, inserted just
     * before the Date column.
     *
     * @param array<string,string> $columns
     * @return array<string,string>
     */
    public function service_list_columns( $columns ): array
    {
        if ( ! is_array( $columns ) ) {
            return $columns;
        }
        $reordered = [];
        foreach ( $columns as $key => $label ) {
            if ( 'date' === $key && ! isset( $reordered['bookaro_price'] ) ) {
                $reordered['bookaro_price']    = __( 'Price', 'mybookaro' );
                $reordered['bookaro_duration'] = __( 'Duration', 'mybookaro' );
            }
            $reordered[ $key ] = $label;
        }
        // No Date column? Append the new columns at the end.
        if ( ! isset( $reordered['bookaro_price'] ) ) {
            $reordered['bookaro_price']    = __( 'Price', 'mybookaro' );
            $reordered['bookaro_duration'] = __( 'Duration', 'mybookaro' );
        }
        return $reordered;
    }

    /**
     * Render the Price / Duration cell values for the Services list table.
     */
    public function render_service_list_column( $column, $post_id ): void
    {
        $post_id = (int) $post_id;
        if ( 'bookaro_price' === $column ) {
            $price = get_post_meta( $post_id, BOOKARO_SERVICE_PRICE_META, true );
            if ( '' === $price || null === $price ) {
                echo '&mdash;';
                return;
            }
            echo esc_html(
                function_exists( 'bookaro_format_price' )
                    ? bookaro_format_price( (float) $price )
                    : number_format_i18n( (float) $price, 2 )
            );
            return;
        }
        if ( 'bookaro_duration' === $column ) {
            $duration = get_post_meta( $post_id, BOOKARO_SERVICE_DURATION_MINUTES_META, true );
            if ( '' === $duration ) {
                $duration = get_post_meta( $post_id, BOOKARO_SERVICE_DURATION_META, true );
            }
            $duration = (int) $duration;
            if ( $duration < 1 ) {
                echo '&mdash;';
                return;
            }
            /* translators: %d: number of minutes. */
            echo esc_html( sprintf( _n( '%d min', '%d min', $duration, 'mybookaro' ), $duration ) );
            return;
        }
    }

    public function register_post_type(): void
    {
        if ( ! $this->generic_mode_enabled() ) {
            return;
        }
        $labels = [
            'name'               => __( 'Services', 'mybookaro' ),
            'singular_name'      => __( 'Service', 'mybookaro' ),
            'add_new'            => __( 'Add New', 'mybookaro' ),
            'add_new_item'       => __( 'Add New Service', 'mybookaro' ),
            'edit_item'          => __( 'Edit Service', 'mybookaro' ),
            'new_item'           => __( 'New Service', 'mybookaro' ),
            'view_item'          => __( 'View Service', 'mybookaro' ),
            'search_items'       => __( 'Search Services', 'mybookaro' ),
            'not_found'          => __( 'No services found.', 'mybookaro' ),
            'not_found_in_trash' => __( 'No services found in Trash.', 'mybookaro' ),
            'all_items'          => __( 'Services', 'mybookaro' ),
            'menu_name'          => __( 'Services', 'mybookaro' ),
        ];

        $show_ui = (bool) apply_filters( 'bookaro_show_service_ui', true );
        $menu    = $show_ui ? 'bookaro-bookings' : false;

        register_post_type(
            BOOKARO_SERVICE_POST_TYPE,
            [
                'labels'             => $labels,
                'public'             => true,
                'publicly_queryable' => true,
                'show_ui'            => $show_ui,
                'show_in_menu'       => $menu,
                'show_in_rest'       => true,
                'has_archive'        => false,
                'rewrite'            => [ 'slug' => 'services' ],
                'menu_position'      => 26,
                'menu_icon'          => 'dashicons-clipboard',
                'supports'           => [ 'title', 'editor', 'author' ],
                // Use a dedicated custom capability_type so the CPT gets its
                // own primitive cap names (edit_bookaro_service / _services /
                // edit_others_bookaro_services / ...). Admins are granted all
                // of these via the user_has_cap filter in register_hooks().
                //
                // Do NOT map any of the post caps in `capabilities` directly
                // to `manage_options` — WordPress reverse-records that
                // mapping in the global $post_type_meta_caps array, so a
                // later current_user_can( 'manage_options' ) call (no post
                // arg) recurses into `delete_post`, which returns
                // `do_not_allow` and locks admins out of unrelated screens
                // (Porto's Speed Optimize Wizard / Setup Wizard, etc.).
                'capability_type'    => [ 'bookaro_service', 'bookaro_services' ],
                'map_meta_cap'       => true,
            ]
        );
    }

    public function register_meta(): void
    {
        if ( ! $this->generic_mode_enabled() ) {
            return;
        }
        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_LABEL_META,
            [
                'type'              => 'string',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'sanitize_text_field',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_DESCRIPTION_META,
            [
                'type'              => 'string',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'wp_kses_post',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_PRICE_META,
            [
                'type'              => 'number',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => fn( $value ) => (float) $value,
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_DURATION_META,
            [
                'type'              => 'integer',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'absint',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_DURATION_MINUTES_META,
            [
                'type'              => 'integer',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'absint',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_LISTING_META,
            [
                'type'              => 'integer',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'absint',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_SCOPE_META,
            [
                'type'              => 'string',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'sanitize_key',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_PROVIDER_META,
            [
                'type'              => 'integer',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'absint',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_OWNER_META,
            [
                'type'              => 'string',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'sanitize_key',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_SHARED_META,
            [
                'type'              => 'integer',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'absint',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );

        register_post_meta(
            BOOKARO_SERVICE_POST_TYPE,
            BOOKARO_SERVICE_IS_SHARED_META,
            [
                'type'              => 'integer',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'absint',
                'auth_callback'     => fn() => current_user_can( 'edit_posts' ),
            ]
        );
    }

    public function register_meta_box(): void
    {
        if ( ! $this->generic_mode_enabled() ) {
            return;
        }
        add_meta_box(
            'bookaro-service-details',
            __( 'Service Details', 'mybookaro' ),
            [ $this, 'render_meta_box' ],
            BOOKARO_SERVICE_POST_TYPE,
            'normal',
            'default'
        );
    }

    public function render_meta_box( \WP_Post $post ): void
    {
        if ( ! $this->generic_mode_enabled() ) {
            return;
        }
        $is_single_business = $this->is_single_business_mode();
        wp_nonce_field( 'bookaro_service_details', 'bookaro_service_details_nonce' );

        $label    = (string) get_post_meta( $post->ID, BOOKARO_SERVICE_LABEL_META, true );
        if ( '' === $label ) {
            $label = $post->post_title;
        }
        $price    = get_post_meta( $post->ID, BOOKARO_SERVICE_PRICE_META, true );
        $duration = get_post_meta( $post->ID, BOOKARO_SERVICE_DURATION_MINUTES_META, true );
        if ( '' === $duration ) {
            $duration = get_post_meta( $post->ID, BOOKARO_SERVICE_DURATION_META, true );
        }
        $listing  = (int) get_post_meta( $post->ID, BOOKARO_SERVICE_LISTING_META, true );
        $listing_ids = get_post_meta( $post->ID, BOOKARO_SERVICE_LISTING_META, false );
        if ( ! is_array( $listing_ids ) ) {
            $listing_ids = [];
        }
        $listing_ids = array_values( array_filter( array_map( 'absint', $listing_ids ) ) );
        if ( empty( $listing_ids ) && $listing > 0 ) {
            $listing_ids = [ $listing ];
        }
        $owner_type = sanitize_key( (string) get_post_meta( $post->ID, BOOKARO_SERVICE_OWNER_META, true ) );
        if ( ! in_array( $owner_type, [ 'admin', 'provider' ], true ) ) {
            $owner_type = ( $is_single_business || ! current_user_can( 'manage_options' ) ) ? 'provider' : 'admin';
        }
        if ( $is_single_business && 'admin' === $owner_type ) {
            // In Single Business, keep wp-admin service creation aligned with provider-owned runtime behavior.
            $owner_type = 'provider';
        }
        $shared = absint( get_post_meta( $post->ID, BOOKARO_SERVICE_IS_SHARED_META, true ) );
        if ( $shared < 1 ) {
            $shared = absint( get_post_meta( $post->ID, BOOKARO_SERVICE_SHARED_META, true ) );
        }
        if ( 'provider' === $owner_type ) {
            $shared = 0;
        }
        if ( empty( $listing_ids ) ) {
            $shared = 1;
        }

        $listing_type = function_exists( 'bookaro_get_allowed_listing_post_types' )
            ? bookaro_get_allowed_listing_post_types()
            : [ BOOKARO_PROVIDER_POST_TYPE ];
        if ( empty( $listing_type ) ) {
            $listing_type = [ BOOKARO_PROVIDER_POST_TYPE ];
        }
        $listings = get_posts( [
            'post_type'      => $listing_type,
            'posts_per_page' => -1,
            'orderby'        => 'title',
            'order'          => 'ASC',
        ] );
        $allowed_pages = function_exists( 'bookaro_get_allowed_listing_pages' )
            ? bookaro_get_allowed_listing_pages()
            : [];
        if ( ! empty( $allowed_pages ) ) {
            $listings = array_values( array_filter( $listings, static function( \WP_Post $listing_post ) use ( $allowed_pages ): bool {
                if ( $listing_post->post_type !== 'page' ) {
                    return true;
                }
                return in_array( (int) $listing_post->ID, $allowed_pages, true );
            } ) );
        }
        ?>
        <p>
            <label for="bookaro-service-label"><?php esc_html_e( 'Service Label', 'mybookaro' ); ?></label><br />
            <input
                type="text"
                class="regular-text"
                id="bookaro-service-label"
                name="bookaro_service_label"
                value="<?php echo esc_attr( $label ); ?>"
            />
        </p>
        <p>
            <?php if ( 'provider' === $owner_type ) : ?>
                <label for="bookaro-service-listing"><?php esc_html_e( 'Provider Listing', 'mybookaro' ); ?></label><br />
                <select id="bookaro-service-listing" name="bookaro_service_listing">
                    <option value="0">
                        <?php echo esc_html( $is_single_business ? __( 'No listing (use Default Provider)', 'mybookaro' ) : __( 'Select a provider listing', 'mybookaro' ) ); ?>
                    </option>
                    <?php foreach ( $listings as $listing_post ) : ?>
                        <option value="<?php echo esc_attr( $listing_post->ID ); ?>" <?php selected( $listing, $listing_post->ID ); ?>>
                            <?php echo esc_html( $listing_post->post_title ); ?>
                        </option>
                    <?php endforeach; ?>
                </select>
            <?php else : ?>
                <label style="display:inline-flex; align-items:center; gap:8px; margin-bottom:8px;">
                    <input
                        type="checkbox"
                        id="bookaro-service-shared"
                        name="bookaro_service_shared"
                        value="1"
                        <?php checked( $shared, 1 ); ?>
                    />
                    <?php esc_html_e( 'Applies to all listings (Global Service)', 'mybookaro' ); ?>
                </label>
                <br />
                <label for="bookaro-service-listings"><?php esc_html_e( 'Limit to Listings (optional)', 'mybookaro' ); ?></label><br />
                <select id="bookaro-service-listings" name="bookaro_service_listings[]" multiple size="6" style="min-width: 320px;">
                    <?php foreach ( $listings as $listing_post ) : ?>
                        <option value="<?php echo esc_attr( $listing_post->ID ); ?>" <?php selected( in_array( (int) $listing_post->ID, $listing_ids, true ), true ); ?>>
                            <?php echo esc_html( $listing_post->post_title ); ?>
                        </option>
                    <?php endforeach; ?>
                </select>
                <p class="description" style="margin:6px 0 0;"><?php esc_html_e( 'Leave empty to apply to all listings.', 'mybookaro' ); ?></p>
            <?php endif; ?>
        </p>
        <p>
            <label for="bookaro-service-price"><?php esc_html_e( 'Price', 'mybookaro' ); ?></label><br />
            <input
                type="number"
                class="small-text"
                id="bookaro-service-price"
                name="bookaro_service_price"
                step="0.01"
                min="0"
                value="<?php echo esc_attr( $price ); ?>"
            />
        </p>
        <p>
            <label for="bookaro-service-duration"><?php esc_html_e( 'Duration (minutes)', 'mybookaro' ); ?></label><br />
            <input
                type="number"
                class="small-text"
                id="bookaro-service-duration"
                name="bookaro_service_duration"
                step="1"
                min="0"
                value="<?php echo esc_attr( $duration ); ?>"
            />
        </p>
        <?php
    }

    public function save_meta( int $post_id ): void
    {
        static $updating_title = false;
        if ( ! $this->generic_mode_enabled() ) {
            return;
        }
        $is_single_business = $this->is_single_business_mode();
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return;
        }

        if (
            empty( $_POST['bookaro_service_details_nonce'] )
            || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['bookaro_service_details_nonce'] ) ), 'bookaro_service_details' )
        ) {
            return;
        }

        if ( ! current_user_can( 'edit_post', $post_id ) ) {
            return;
        }

        $existing_owner = sanitize_key( (string) get_post_meta( $post_id, BOOKARO_SERVICE_OWNER_META, true ) );
        if ( 'admin' === $existing_owner && ! current_user_can( 'manage_options' ) ) {
            return;
        }

        if ( array_key_exists( 'bookaro_service_label', $_POST ) && ! $updating_title ) {
            $label = sanitize_text_field( wp_unslash( $_POST['bookaro_service_label'] ) );
            if ( '' !== $label ) {
                $post = get_post( $post_id );
                if ( $post && $post->post_title !== $label ) {
                    $updating_title = true;
                    wp_update_post( [
                        'ID'         => $post_id,
                        'post_title' => $label,
                    ] );
                    $updating_title = false;
                }
                update_post_meta( $post_id, BOOKARO_SERVICE_LABEL_META, $label );
            }
        }

        $post = get_post( $post_id );
        if ( $post ) {
            $existing_label = (string) get_post_meta( $post_id, BOOKARO_SERVICE_LABEL_META, true );
            if ( '' === $existing_label ) {
                update_post_meta( $post_id, BOOKARO_SERVICE_LABEL_META, (string) $post->post_title );
            }
            update_post_meta( $post_id, BOOKARO_SERVICE_DESCRIPTION_META, (string) $post->post_content );
        }

        $listing_id = array_key_exists( 'bookaro_service_listing', $_POST )
            ? absint( wp_unslash( $_POST['bookaro_service_listing'] ) )
            : (int) get_post_meta( $post_id, BOOKARO_SERVICE_LISTING_META, true );
        $listing_ids = [];
        if ( array_key_exists( 'bookaro_service_listings', $_POST ) ) {
            // Every entry is forced through absint() below, which is the
            // appropriate sanitizer for listing IDs.
            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
            $raw_ids = wp_unslash( $_POST['bookaro_service_listings'] );
            if ( is_array( $raw_ids ) ) {
                $listing_ids = array_values( array_filter( array_map( 'absint', $raw_ids ) ) );
            }
        }

        $shared = ! empty( $_POST['bookaro_service_shared'] ) ? 1 : 0;

        $owner_type = 'admin';
        if ( $is_single_business ) {
            $owner_type = 'provider';
        } elseif ( 'provider' === $existing_owner ) {
            $owner_type = 'provider';
        } elseif ( ! current_user_can( 'manage_options' ) ) {
            $owner_type = 'provider';
        }
        if ( ! in_array( $owner_type, [ 'admin', 'provider' ], true ) ) {
            $owner_type = 'admin';
        }
        if ( $is_single_business ) {
            $owner_type = 'provider';
        }

        $scope = 'provider';
        if ( 'provider' === $owner_type ) {
            $shared = 0;
            if ( $listing_id < 1 ) {
                $listing_id = (int) get_post_meta( $post_id, BOOKARO_SERVICE_LISTING_META, true );
            }
            $listing_ids = $listing_id > 0 ? [ $listing_id ] : [];
            $scope = 'provider';
        } else {
            if ( $shared ) {
                $listing_ids = [];
                $scope = 'global';
            } elseif ( empty( $listing_ids ) ) {
                $shared = 1;
                $scope = 'global';
            } else {
                $shared = 0;
                $scope = 'listing';
            }
        }

        if ( 'provider' === $owner_type && $listing_id < 1 && ! $is_single_business ) {
            return;
        }

        delete_post_meta( $post_id, BOOKARO_SERVICE_LISTING_META );
        if ( 'provider' === $owner_type ) {
            if ( $listing_id > 0 ) {
                update_post_meta( $post_id, BOOKARO_SERVICE_LISTING_META, $listing_id );
            }
        } elseif ( ! $shared ) {
            foreach ( $listing_ids as $assigned_id ) {
                add_post_meta( $post_id, BOOKARO_SERVICE_LISTING_META, $assigned_id );
            }
        }
        update_post_meta( $post_id, BOOKARO_SERVICE_OWNER_META, $owner_type );
        update_post_meta( $post_id, BOOKARO_SERVICE_SHARED_META, $shared );
        update_post_meta( $post_id, BOOKARO_SERVICE_IS_SHARED_META, $shared );
        update_post_meta( $post_id, BOOKARO_SERVICE_SCOPE_META, $scope );

        $provider_id = 0;
        if ( 'provider' === $owner_type ) {
            if ( $listing_id > 0 ) {
                $provider_id = function_exists( 'bookaro_get_listing_owner_id' )
                    ? (int) bookaro_get_listing_owner_id( $listing_id )
                    : 0;
            } elseif ( $is_single_business ) {
                $provider_id = function_exists( 'bookaro_get_option' )
                    ? absint( bookaro_get_option( 'default_provider_id', 0 ) )
                    : 0;
                if ( $provider_id < 1 || ! get_user_by( 'ID', $provider_id ) ) {
                    $provider_id = get_current_user_id();
                }
            }
        }
        update_post_meta( $post_id, BOOKARO_SERVICE_PROVIDER_META, $provider_id );

        if ( array_key_exists( 'bookaro_service_price', $_POST ) ) {
            update_post_meta(
                $post_id,
                BOOKARO_SERVICE_PRICE_META,
                floatval( sanitize_text_field( wp_unslash( $_POST['bookaro_service_price'] ) ) )
            );
        }

        if ( array_key_exists( 'bookaro_service_duration', $_POST ) ) {
            update_post_meta(
                $post_id,
                BOOKARO_SERVICE_DURATION_META,
                absint( wp_unslash( $_POST['bookaro_service_duration'] ) )
            );
            update_post_meta(
                $post_id,
                BOOKARO_SERVICE_DURATION_MINUTES_META,
                absint( wp_unslash( $_POST['bookaro_service_duration'] ) )
            );
        }
    }

    private function generic_mode_enabled(): bool
    {
        if ( defined( 'BOOKARO_ENABLE_GENERIC_MODE' ) && ! BOOKARO_ENABLE_GENERIC_MODE ) {
            return false;
        }
        return function_exists( 'bookaro_get_integration_mode' )
            && 'generic' === bookaro_get_integration_mode();
    }

    private function is_single_business_mode(): bool
    {
        if ( function_exists( 'bookaro_is_single_business_site' ) ) {
            return (bool) bookaro_is_single_business_site();
        }
        if ( ! function_exists( 'bookaro_get_site_type' ) ) {
            return false;
        }
        return 'single_business' === sanitize_key( (string) bookaro_get_site_type() );
    }
}
