<?php

use WeDevs\Dokan\Cache;
use WeDevs\Dokan\Utilities\OrderUtil;

/**
 * Dokan Admin menu position
 *
 * @since 3.0.0
 *
 * @return string
 */
function dokan_admin_menu_position() {
    return apply_filters( 'dokan_menu_position', '55.4' );
}

/**
 * Dokan Admin menu capability
 *
 * @since 3.0.0
 *
 * @return string
 */
function dokana_admin_menu_capability() {
    return dokan_admin_menu_capability();
}

if ( ! function_exists( 'dokan_admin_menu_capability' ) ) {
    /**
     * Dokan Admin menu capability
     *
     * @since 3.8.3
     *
     * @return string
     */
    function dokan_admin_menu_capability() {
        return apply_filters( 'dokan_menu_capability', 'manage_woocommerce' );
    }
}

/**
 * Dokan Get current user id
 *
 * @since 2.7.3
 *
 * @return int
 */
function dokan_get_current_user_id() {
    if ( current_user_can( 'vendor_staff' ) ) {
        $staff_id  = get_current_user_id();
        $vendor_id = (int) get_user_meta( $staff_id, '_vendor_id', true );

        if ( empty( $vendor_id ) ) {
            return $staff_id;
        }

        return $vendor_id;
    }

    return get_current_user_id();
}

/**
 * Check if a user is seller
 *
 * @since 3.14.9 Added `$exclude_staff` as optional parameter
 *
 * @param int  $user_id       User ID
 * @param bool $exclude_staff Exclude staff
 *
 * @return bool
 */
function dokan_is_user_seller( $user_id, $exclude_staff = false ) {
    if ( $exclude_staff && user_can( $user_id, 'vendor_staff' ) ) {
        return false;
    }

    return user_can( $user_id, 'dokandar' );
}

/**
 * Check if a user is customer
 *
 * @param int $user_id
 *
 * @return bool
 */
function dokan_is_user_customer( $user_id ) {
    if ( ! user_can( $user_id, 'customer' ) ) {
        return false;
    }

    return true;
}

/**
 * Get reserved URL slugs that cannot be used for custom slugs like store base
 *
 * @since 4.1.5
 *
 * @return array List of reserved slugs
 */
function dokan_get_reserved_url_slugs() {
    $reserved_slugs = [
        's',
        'p',
        'page',
        'paged',
        'author',
        'feed',
        'search',
        'post',
        'tag',
        'category',
        'attachment',
        'name',
        'order',
        'orderby',
        'rest',
        'rest_route',
        'wp-json',
        'shop',
        'cart',
        'checkout',
    ];

    /**
     * Filter the list of reserved URL slugs that cannot be used for custom slugs like store base.
     *
     * @since 4.1.5
     *
     * @param array $reserved_slugs List of reserved slugs.
     */
    return apply_filters( 'dokan_reserved_url_slugs', $reserved_slugs );
}

/**
 * Check if current user is the product author
 *
 * @param int      $product_id
 *
 * @return bool
 */
function dokan_is_product_author( $product_id = 0 ) {
    global $post;

    if ( ! $product_id ) {
        $author = $post->post_author;
    } else {
        $author = get_post_field( 'post_author', $product_id );
    }

    return absint( $author ) === apply_filters( 'dokan_is_product_author', dokan_get_current_user_id(), $product_id );
}

/**
 * Check if it's a store page
 *
 * @return bool
 */
function dokan_is_store_page() {
    $custom_store_url = dokan_get_option( 'custom_store_url', 'dokan_general', 'store' );

    if ( get_query_var( $custom_store_url ) ) {
        return true;
    }

    return false;
}

/**
 * Check if it's product edit page
 *
 * @since 3.0
 *
 * @return bool
 */
function dokan_is_product_edit_page() {
    return get_query_var( 'edit' ) && is_singular( 'product' );
}

/**
 * Check if it's a Seller Dashboard page
 *
 * @since 2.4.9
 *
 * @return bool
 */
function dokan_is_seller_dashboard() {
    global $wp_query;

    $page_id = apply_filters( 'dokan_get_dashboard_page_id', dokan_get_option( 'dashboard', 'dokan_pages' ) );

    if ( ! $page_id ) {
        return false;
    }

    if ( ! $wp_query ) {
        return false;
    }

    if ( absint( $page_id ) === apply_filters( 'dokan_get_current_page_id', $wp_query->queried_object_id ) ) {
        return true;
    }

    return false;
}

/**
 * Redirect to login page if not already logged in
 *
 * @return void
 */
function dokan_redirect_login() {
    if ( ! is_user_logged_in() ) {
        $url = apply_filters( 'dokan_redirect_login', dokan_get_page_url( 'myaccount', 'woocommerce' ) );
        wp_safe_redirect( $url );
        exit();
    }
}

/**
 * If the current user is not seller, redirect to homepage
 *
 * @param string $redirect
 */
function dokan_redirect_if_not_seller( $redirect = '' ) {
    if ( ! dokan_is_user_seller( dokan_get_current_user_id() ) ) {
        $redirect = empty( $redirect ) ? home_url( '/' ) : $redirect;

        wp_safe_redirect( $redirect );
        exit();
    }
}

/**
 * Count post type from a user
 *
 * @param string $post_type
 * @param int    $user_id
 * @param array  $exclude_product_types The product types that will be excluded from count
 *
 * @return array
 */
function dokan_count_posts( $post_type, $user_id, $exclude_product_types = [ 'booking', 'auction' ] ) {
    // get all function arguments as key => value pairs
    $args = apply_filters( 'dokan_count_posts_args', get_defined_vars() );

    $cache_group = "seller_product_data_$user_id";
    $cache_key   = 'count_posts_' . md5( wp_json_encode( $args ) );
    $counts      = Cache::get( $cache_key, $cache_group );

    if ( false === $counts ) {
        $results = apply_filters( 'dokan_count_posts', null, $post_type, $user_id, $exclude_product_types );

        if ( ! $results ) {
            global $wpdb;
            $exclude_product_types_text = "'" . implode( "', '", esc_sql( $exclude_product_types ) ) . "'";

            // @codingStandardsIgnoreStart
            $results = $wpdb->get_results(
                $wpdb->prepare(
                    "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} as posts
                            INNER JOIN {$wpdb->term_relationships} AS term_relationships ON posts.ID = term_relationships.object_id
                            INNER JOIN {$wpdb->term_taxonomy} AS term_taxonomy ON term_relationships.term_taxonomy_id = term_taxonomy.term_taxonomy_id
                            INNER JOIN {$wpdb->terms} AS terms ON term_taxonomy.term_id = terms.term_id
                            WHERE
                                term_taxonomy.taxonomy = 'product_type'
                            AND terms.slug NOT IN ({$exclude_product_types_text})
                            AND posts.post_type = %s
                            AND posts.post_author = %d
                                GROUP BY posts.post_status",
                    $post_type,
                    $user_id
                ),
                ARRAY_A
            );
            // @codingStandardsIgnoreEnd
        }

        $post_status = array_keys( dokan_get_post_status() );
        $counts      = array_fill_keys( get_post_stati(), 0 );
        $total       = 0;

        foreach ( $results as $row ) {
            if ( ! in_array( $row['post_status'], $post_status, true ) ) {
                continue;
            }

            $counts[ $row['post_status'] ] = (int) $row['num_posts'];
            $total                         += (int) $row['num_posts'];
        }

        $counts['total'] = $total;
        $counts          = (object) $counts;

        Cache::set( $cache_key, $counts, $cache_group );
    }

    return $counts;
}

/**
 * Count stock product type from a user
 *
 * @since 3.2.5
 *
 * @param string $post_type
 * @param int    $user_id
 * @param string $stock_type
 * @param array  $exclude_product_types
 *
 * @return int $counts
 */
function dokan_count_stock_posts( $post_type, $user_id, $stock_type, $exclude_product_types = [ 'booking', 'auction' ] ) {
    global $wpdb;

    $cache_group = 'seller_product_stock_data_' . $user_id;
    $cache_key   = apply_filters( 'dokan_count_stock_posts_cache_key', "count_stock_posts_{$user_id}_{$post_type}_{$stock_type}", $post_type, $user_id, $stock_type );
    $counts      = Cache::get( $cache_key, $cache_group );

    if ( false === $counts ) {
        $results = apply_filters( 'dokan_count_posts_' . $stock_type, null, $post_type, $user_id, $stock_type, $exclude_product_types );
        $exclude_product_types_text = "'" . implode( "', '", esc_sql( $exclude_product_types ) ) . "'";

        if ( ! $results ) {
            // @codingStandardsIgnoreStart
            $results = $wpdb->get_results(
                $wpdb->prepare(
                    "SELECT p.post_status, COUNT(DISTINCT p.ID) AS num_posts
                    FROM {$wpdb->prefix}posts as p INNER JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
                    WHERE p.post_type = %s
                    AND p.post_author = %d
                    AND pm.meta_key   = '_stock_status'
                    AND pm.meta_value = %s
                    AND p.ID IN (
                        SELECT tr.object_id FROM {$wpdb->prefix}terms AS t
                        LEFT JOIN {$wpdb->prefix}term_taxonomy AS tt ON t.term_id = tt.term_taxonomy_id
                        LEFT JOIN {$wpdb->prefix}term_relationships AS tr ON t.term_id = tr.term_taxonomy_id
                        WHERE tt.taxonomy = 'product_type' AND t.slug NOT IN ({$exclude_product_types_text})
                    )
                    GROUP BY p.post_status",
                    $post_type,
                    $user_id,
                    $stock_type
                ),
                ARRAY_A
            );
            // @codingStandardsIgnoreEnd
        }

        $post_status = array_keys( dokan_get_post_status() );
        $total       = 0;

        foreach ( $results as $row ) {
            if ( ! in_array( $row['post_status'], $post_status, true ) ) {
                continue;
            }

            $total += (int) $row['num_posts'];
        }

        $counts = $total;

        Cache::set( $cache_key, $counts, $cache_group );
    }

    return $counts;
}

/**
 * Get comment count based on post type and user id
 *
 * @param string   $post_type
 * @param int      $user_id
 *
 * @return array
 */
function dokan_count_comments( $post_type, $user_id ) {
    global $wpdb;

    $cache_group = "count_{$post_type}_comments_{$user_id}";
    $cache_key   = 'comments';
    $counts      = Cache::get( $cache_key, $cache_group );

    if ( $counts === false ) {
        $count = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->prepare(
                "SELECT c.comment_approved, COUNT( * ) AS num_comments
                FROM $wpdb->comments as c, $wpdb->posts as p
                WHERE p.post_author = %d AND
                    p.post_status = 'publish' AND
                    c.comment_post_ID = p.ID AND
                    p.post_type = %s
                GROUP BY c.comment_approved",
                $user_id,
                $post_type
            ),
            ARRAY_A
        );

        $total    = 0;
        $counts   = [
            'moderated' => 0,
            'approved'  => 0,
            'spam'      => 0,
            'trash'     => 0,
            'total'     => 0,
        ];
        $statuses = [
            '0'            => 'moderated',
            '1'            => 'approved',
            'spam'         => 'spam',
            'trash'        => 'trash',
            'post-trashed' => 'post-trashed',
        ];

        foreach ( $count as $row ) {
            if ( isset( $statuses[ $row['comment_approved'] ] ) ) {
                $counts[ $statuses[ $row['comment_approved'] ] ] = (int) $row['num_comments'];
                $total += (int) $row['num_comments'];
            }
        }
        $counts['total'] = $total;

        $counts = (object) $counts;
        Cache::set( $cache_key, $counts, $cache_group );
    }

    return $counts;
}

/**
 * Get total pageview for a seller
 *
 * @param int   $seller_id
 *
 * @return int
 */
function dokan_author_pageviews( $seller_id ) {
    global $wpdb;

    $cache_key = "pageview_{$seller_id}";
    $pageview  = Cache::get( $cache_key );

    if ( false === $pageview ) {
        $count = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->prepare(
                "SELECT SUM(meta_value) as pageview
                FROM {$wpdb->postmeta} AS meta
                LEFT JOIN {$wpdb->posts} AS p ON p.ID = meta.post_id
                WHERE meta.meta_key = 'pageview' AND p.post_author = %d AND p.post_status IN ('publish', 'pending', 'draft')",
                $seller_id
            )
        );

        $pageview = $count->pageview;

        Cache::set( $cache_key, $pageview );
    }

    return $pageview;
}

if ( ! function_exists( 'dokan_get_seller_percentage' ) ) {

    /**
     * Get store seller percentage settings
     *
     * @deprecated 3.14.0 Do Not Use This Function
     *
     * @param int $seller_id
     * @param int $product_id
     *
     * @return int
     */
    function dokan_get_seller_percentage( $seller_id = 0, $product_id = 0, $category_id = 0 ) {
        wc_deprecated_function( __FUNCTION__, '3.14.0', 'dokan()->commission->get_commission()' );

        $commission_data = dokan()->commission->get_commission(
            [
                'vendor_id'   => $seller_id,
                'product_id'  => $product_id,
                'category_id' => $category_id,
            ]
        );

        $commission_val = $commission_data->get_vendor_earning();

        return apply_filters( 'dokan_get_seller_percentage', $commission_val, $seller_id, $product_id );
    }
}

/**
 * Get Dokan commission type by seller or product or both
 *
 * @deprecated 3.14.0 Do Not Use This Function
 *
 * @since 2.6.9
 *
 * @param int $seller_id
 * @param int $product_id
 *
 * @return string $type
 */
function dokan_get_commission_type( $seller_id = 0, $product_id = 0, $category_id = 0 ) {
    wc_deprecated_function( __FUNCTION__, '3.14.0', 'dokan()->commission->get_commission()' );

    $commission_data = dokan()->commission->get_commission(
        [
            'vendor_id'   => $seller_id,
            'product_id'  => $product_id,
            'category_id' => $category_id,
        ]
    );

    return $commission_data->get_type();
}

/**
 * Get the default product status for new and edited product for seller based on settings
 *
 * @since 3.8.2
 *
 * @param int|null $seller_id
 *
 * @return string
 */
function dokan_get_default_product_status( $seller_id = null ) {
    $seller_id  = null === $seller_id ? dokan_get_current_user_id() : $seller_id;
    $is_trusted = dokan_is_seller_trusted( $seller_id );
    $status     = 'pending';

    if ( $is_trusted ) {
        $status = 'publish';
    }

    // below code will be removed on a future version of Dokan Lite
    if ( dokan()->is_pro_exists() && version_compare( DOKAN_PRO_PLUGIN_VERSION, '3.8.3', '<' ) ) {
        $status = 'publish' === $status ? $status : dokan_get_option( 'product_status', 'dokan_selling', 'pending' );
    }

    $status = apply_filters_deprecated( 'dokan_get_new_post_status', [ $status, $seller_id, $is_trusted ], '3.8.2', 'dokan_get_default_product_status' );

    return apply_filters( 'dokan_get_default_product_status', $status, $seller_id, $is_trusted );
}

/**
 * Get product status based on user id and settings
 *
 * @since 3.7.20 added a new filter hook `dokan_get_new_post_status`
 *
 * @since 3.8.2 made the function deprecated
 *
 * @param int|null $seller_id
 *
 * @deprecated 3.8.2 use `dokan_get_default_product_status` instead
 *
 * @return string
 */
function dokan_get_new_post_status( $seller_id = null ) {
    return dokan_get_default_product_status( $seller_id );
}

/**
 * Function to get the client ip address
 *
 * @since 3.3.1 Updated some logic
 *
 * @return string
 */
function dokan_get_client_ip() {
    if ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
        $ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REAL_IP'] ) );
    } elseif ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
        $ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_CLIENT_IP'] ) );
    } elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
        // Proxy servers can send through this header like this: X-Forwarded-For: client1, proxy1, proxy2
        // Make sure we always only send through the first IP in the list which should always be the client IP.
        $ipaddress = (string) rest_is_ip_address( trim( current( preg_split( '/,/', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) ) ) );
    } elseif ( isset( $_SERVER['HTTP_X_FORWARDED'] ) ) {
        $ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED'] ) );
    } elseif ( isset( $_SERVER['HTTP_FORWARDED_FOR'] ) ) {
        $ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_FORWARDED_FOR'] ) );
    } elseif ( isset( $_SERVER['HTTP_FORWARDED'] ) ) {
        $ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_FORWARDED'] ) );
    } elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
        $ipaddress = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
    } else {
        $ipaddress = 'UNKNOWN';
    }

    return $ipaddress;
}

/**
 * Generate an input box based on arguments
 *
 * @param int    $post_id
 * @param string $meta_key
 * @param array  $attr
 * @param string $type
 */
function dokan_post_input_box( $post_id, $meta_key, $attr = [], $type = 'text' ) {
    $placeholder   = isset( $attr['placeholder'] ) ? esc_attr( $attr['placeholder'] ) : '';
    $class         = isset( $attr['class'] ) ? esc_attr( $attr['class'] ) : 'dokan-form-control';
    $name          = isset( $attr['name'] ) ? esc_attr( $attr['name'] ) : $meta_key;
    $value         = isset( $attr['value'] ) ? $attr['value'] : get_post_meta( $post_id, $meta_key, true );
    $size          = isset( $attr['size'] ) ? $attr['size'] : 30;
    $required      = isset( $attr['required'] ) ? 'required' : '';

    switch ( $type ) {
        case 'text':
            ?>
            <input <?php echo esc_attr( $required ); ?>
                type="text" name="<?php echo esc_attr( $name ); ?>"
                id="<?php echo esc_attr( $name ); ?>"
                value="<?php echo esc_attr( $value ); ?>"
                class="<?php echo esc_attr( $class ); ?>"
                placeholder="<?php echo esc_attr( $placeholder ); ?>">
            <?php
            break;

        case 'price':
            ?>
            <input <?php echo esc_attr( $required ); ?>
                type="text" name="<?php echo esc_attr( $name ); ?>"
                id="<?php echo esc_attr( $name ); ?>"
                value="<?php echo esc_attr( wc_format_localized_price( $value ) ); ?>"
                class="wc_input_price <?php echo esc_attr( $class ); ?>"
                placeholder="<?php echo esc_attr( $placeholder ); ?>">
            <?php
            break;

        case 'decimal':
            ?>
            <input <?php echo esc_attr( $required ); ?>
                type="text" name="<?php echo esc_attr( $name ); ?>"
                id="<?php echo esc_attr( $name ); ?>"
                value="<?php echo esc_attr( wc_format_localized_price( $value ) ); ?>"
                class="wc_input_decimal <?php echo esc_attr( $class ); ?>"
                placeholder="<?php echo esc_attr( $placeholder ); ?>">
            <?php
            break;

        case 'textarea':
            $rows = isset( $attr['rows'] ) ? absint( $attr['rows'] ) : 4;
            ?>
            <textarea <?php echo esc_attr( $required ); ?>
                name="<?php echo esc_attr( $name ); ?>"
                id="<?php echo esc_attr( $name ); ?>"
                rows="<?php echo esc_attr( $rows ); ?>"
                class="<?php echo esc_attr( $class ); ?>"
                placeholder="<?php echo esc_attr( $placeholder ); ?>"><?php echo esc_textarea( $value ); ?></textarea>
            <?php
            break;

        case 'checkbox':
            $label = isset( $attr['label'] ) ? $attr['label'] : '';
            $class = ( $class === 'dokan-form-control' ) ? '' : $class;
            ?>

            <label class="<?php echo esc_attr( $class ); ?>" for="<?php echo esc_attr( $name ); ?>">
                <input type="hidden" name="<?php echo esc_attr( $name ); ?>" value="no">
                <input <?php echo esc_attr( $required ); ?> name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $name ); ?>" value="yes" type="checkbox"<?php checked( $value, 'yes' ); ?>>
                <?php echo esc_html( $label ); ?>
            </label>

            <?php
            break;

        case 'select':
            $options = is_array( $attr['options'] ) ? $attr['options'] : [];
            ?>
            <select name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $name ); ?>" class="<?php echo esc_attr( $class ); ?>">
                <?php foreach ( $options as $key => $label ) { ?>
                    <option value="<?php echo esc_attr( $key ); ?>"<?php selected( $value, $key ); ?>><?php echo esc_html( $label ); ?></option>
                <?php } ?>
            </select>

            <?php
            break;

        case 'number':
            $min  = isset( $attr['min'] ) ? $attr['min'] : 0;
            $step = isset( $attr['step'] ) ? $attr['step'] : 'any';
            ?>
            <input <?php echo esc_attr( $required ); ?>
                type="number" name="<?php echo esc_attr( $name ); ?>"
                id="<?php echo esc_attr( $name ); ?>"
                value="<?php echo esc_attr( $value ); ?>"
                class="<?php echo esc_attr( $class ); ?>"
                placeholder="<?php echo esc_attr( $placeholder ); ?>"
                min="<?php echo esc_attr( $min ); ?>"
                step="<?php echo esc_attr( $step ); ?>"
                size="<?php echo esc_attr( $size ); ?>">
            <?php
            break;

        case 'radio':
            $options = is_array( $attr['options'] ) ? $attr['options'] : [];

            foreach ( $options as $key => $label ) {
                ?>
                <label class="<?php echo esc_attr( $class ); ?>" for="<?php echo esc_attr( $key ); ?>">
                    <input name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $key ); ?>" type="radio"<?php checked( $value, $key ); ?>>
                    <?php echo esc_html( $label ); ?>
                </label>

                <?php
            }
            break;
    }
}

/**
 * Get user-friendly post status based on post
 *
 * @param string $status
 *
 * @return string|array
 */
function dokan_get_post_status( $status = '' ) {
    $statuses = apply_filters(
        'dokan_get_post_status', [
            'publish' => __( 'Publish', 'dokan-lite' ),
            'draft'   => __( 'Draft', 'dokan-lite' ),
            'pending' => __( 'Pending Review', 'dokan-lite' ),
            'future'  => __( 'Scheduled', 'dokan-lite' ),
        ]
    );

    if ( $status ) {
        return isset( $statuses[ $status ] ) ? $statuses[ $status ] : '';
    }

    return $statuses;
}

/**
 * Get product available statuses
 *
 * @since 3.8.2
 *
 * @args int|object $product_id
 *
 * @return array
 */
if ( ! function_exists( 'dokan_get_available_post_status' ) ) {

    function dokan_get_available_post_status( $product_id = 0 ) {
        return apply_filters(
            'dokan_post_status',
            [
                'publish' => dokan_get_post_status( 'publish' ),
                'draft'   => dokan_get_post_status( 'draft' ),
                'pending' => dokan_get_post_status( 'pending' ),
            ],
            $product_id
        );
    }
}

/**
 * Get user friendly post status label based class
 *
 * @param string $status
 *
 * @return string|array
 */
function dokan_get_post_status_label_class( $status = '' ) {
    $labels = apply_filters(
        'dokan_get_post_status_label_class', [
            'publish' => 'dokan-label-success',
            'draft'   => 'dokan-label-default',
            'pending' => 'dokan-label-danger',
            'future'  => 'dokan-label-warning',
        ]
    );

    if ( $status ) {
        return isset( $labels[ $status ] ) ? $labels[ $status ] : '';
    }

    return $labels;
}

/**
 * Get readable product type based on product
 *
 * @param string $status
 *
 * @return array
 */
function dokan_get_product_types( $status = '' ) {
    $types = apply_filters(
        'dokan_get_product_types', [
            'simple'   => __( 'Simple Product', 'dokan-lite' ),
            'variable' => __( 'Variable Product', 'dokan-lite' ),
            'grouped'  => __( 'Grouped Product', 'dokan-lite' ),
            'external' => __( 'External/Affiliate Product', 'dokan-lite' ),
        ]
    );

    if ( $status ) {
        return isset( $types[ $status ] ) ? $types[ $status ] : '';
    }

    return $types;
}

/**
 * Helper function for input text field
 *
 * @param string $key
 *
 * @return string
 */
function dokan_posted_input( $key, $array = false ) {
    wc_deprecated_function( 'dokan_posted_input', '3.6.6' );

    return '';
}

/**
 * Helper function for input textarea
 *
 * @param string $key
 *
 * @return string
 */
function dokan_posted_textarea( $key ) {
    wc_deprecated_function( 'dokan_posted_textarea', '3.6.6' );

    return '';
}

/**
 * Get template part implementation for wedocs
 *
 * Looks at the theme directory first
 */
function dokan_get_template_part( $slug, $name = '', $args = [] ) {
    $defaults = [
        'pro' => false,
    ];

    $args = wp_parse_args( $args, $defaults );

    if ( $args && is_array( $args ) ) {
        extract( $args ); // phpcs:ignore
    }

    $template = '';

    // Look in yourtheme/dokan/slug-name.php and yourtheme/dokan/slug.php
    $template_path = ! empty( $name ) ? "{$slug}-{$name}.php" : "{$slug}.php";
    $template      = locate_template( [ dokan()->template_path() . $template_path ] );

    /**
     * Change template directory path filter
     *
     * @since 2.5.3
     */
    $template_path = apply_filters( 'dokan_set_template_path', dokan()->plugin_path() . '/templates', $template, $args );

    // Get default slug-name.php
    if ( ! $template && $name && file_exists( $template_path . "/{$slug}-{$name}.php" ) ) {
        $template = $template_path . "/{$slug}-{$name}.php";
    }

    if ( ! $template && ! $name && file_exists( $template_path . "/{$slug}.php" ) ) {
        $template = $template_path . "/{$slug}.php";
    }

    // Allow 3rd party plugin filter template file from their plugin
    $template = apply_filters( 'dokan_get_template_part', $template, $slug, $name );

    if ( $template ) {
        include $template;
    }
}

/**
 * Get other templates (e.g. product attributes) passing attributes and including the file.
 *
 * @param mixed  $template_name
 * @param array  $args          (default: array())
 * @param string $template_path (default: '')
 * @param string $default_path  (default: '')
 *
 * @return void
 */
function dokan_get_template( $template_name, $args = [], $template_path = '', $default_path = '' ) {
    if ( $args && is_array( $args ) ) {
        extract( $args ); // phpcs:ignore
    }

    $located = dokan_locate_template( $template_name, $template_path, $default_path );

    if ( ! file_exists( $located ) ) {
        _doing_it_wrong( __FUNCTION__, sprintf( '<code>%s</code> does not exist.', esc_html( $located ) ), '2.1' );

        return;
    }

    do_action( 'dokan_before_template_part', $template_name, $template_path, $located, $args );

    include $located;

    do_action( 'dokan_after_template_part', $template_name, $template_path, $located, $args );
}

/**
 * Locate a template and return the path for inclusion.
 *
 * This is the load order:
 *
 *      yourtheme       /   $template_path  /   $template_name
 *      yourtheme       /   $template_name
 *      $default_path   /   $template_name
 *
 * @param mixed  $template_name
 * @param string $template_path (default: '')
 * @param string $default_path  (default: '')
 *
 * @return string
 */
function dokan_locate_template( $template_name, $template_path = '', $default_path = '', $pro = false ) {
    if ( ! $template_path ) {
        $template_path = dokan()->template_path();
    }

    if ( ! $default_path ) {
        $default_path = dokan()->plugin_path() . '/templates/';
    }

    // Look within passed path within the theme - this is priority
    $template = locate_template(
        [
            trailingslashit( $template_path ) . $template_name,
        ]
    );

    // Get default template
    if ( ! $template ) {
        $template = $default_path . $template_name;
    }

    // Return what we found
    return apply_filters( 'dokan_locate_template', $template, $template_name, $template_path );
}

/**
 * Get page permalink based on context
 *
 * @param string $page
 * @param string $context
 * @param string $subpage
 *
 * @return string url of the page
 */
function dokan_get_page_url( $page, $context = 'dokan', $subpage = '' ) {
    if ( $context === 'woocommerce' ) {
        $page_id = wc_get_page_id( $page );
    } else {
        $page_id = dokan_get_option( $page, 'dokan_pages' );
    }

    $url = get_permalink( $page_id );

    if ( $subpage ) {
        $url = dokan_add_subpage_to_url( $url, $subpage );
    }

    return apply_filters( 'dokan_get_page_url', $url, $page_id, $context, $subpage );
}

/**
 * Add subpage to url: this will add wpml like plugin compatibility
 *
 * @since 3.2.14
 *
 * @param string $subpage
 *
 * @param string $url
 *
 * @return false|string
 */
function dokan_add_subpage_to_url( $url, $subpage ) {
    $url_parts         = wp_parse_url( $url );
    $url_parts['path'] = $url_parts['path'] . $subpage;

    return http_build_url( '', $url_parts );
}

/**
 * Get edit product url
 *
 * @param int|WC_Product $product
 * @param bool $is_new_product Is new product. Default `false`.
 *
 * @return string|false on failure
 */
function dokan_edit_product_url( $product, bool $is_new_product = false ) {
    if ( ! $product instanceof WC_Product ) {
        $product = wc_get_product( $product );
    }

    if ( ! $product && ! $is_new_product ) {
        return false;
    }

    if ( ! $product && $is_new_product ) {
        $product = new WC_Product();
    }

    $product_id      = $is_new_product ? 0 : $product->get_id();
    $legacy_switcher = dokan_get_container()->get( \WeDevs\Dokan\Admin\Dashboard\LegacySwitcher::class );

    // Resolve the user whose editor preference should drive the URL — prefer the
    // product author so email/admin contexts honor the vendor's choice.
    $user_id = $product_id ? (int) get_post_field( 'post_author', $product_id ) : get_current_user_id();

    if ( $legacy_switcher->is_product_editor_legacy_preferred( $user_id ) ) {
        $url = add_query_arg(
            [
                'product_id'                => $product_id,
                'action'                    => 'edit',
                '_dokan_edit_product_nonce' => wp_create_nonce( 'dokan_edit_product_nonce' ),
            ],
            dokan_get_navigation_url( 'products' )
        );
    } else {
        $url = $legacy_switcher->get_new_product_editor_url( $product_id );
    }

    return apply_filters( 'dokan_get_edit_product_url', $url, $product );
}

/**
 * Ads additional columns to admin user table
 *
 * @param array $columns
 *
 * @return array
 */
function dokan_admin_product_columns( $columns ) {
    $columns['admin_commission'] = __( 'Commission', 'dokan-lite' );
    $columns['author']           = __( 'Author', 'dokan-lite' );

    return $columns;
}

add_filter( 'manage_edit-product_columns', 'dokan_admin_product_columns' );

/**
 * Get the value of a settings field
 *
 * @param string $option  settings field name
 * @param string $section the section name this field belongs to
 * @param string $default_value default text if it's not found
 *
 * @return mixed
 */
function dokan_get_option( $option, $section, $default_value = '' ) {
    [ $option, $section ] = dokan_admin_settings_rearrange_map( $option, $section );

    $options = get_option( $section );

    if ( isset( $options[ $option ] ) ) {
        return $options[ $option ];
    }

    return $default_value;
}

/**
 * Redirect users from standard WordPress register page to woocommerce
 * my account page
 *
 * @global string $action
 */
function dokan_redirect_to_register() {
    global $action;

    if ( $action === 'register' ) {
        wp_safe_redirect( dokan_get_page_url( 'myaccount', 'woocommerce' ) );
        exit;
    }
}

add_action( 'login_init', 'dokan_redirect_to_register' );

/**
 * Check if the seller is enabled
 *
 * @since 3.10.0 New filter added `dokan_is_seller_enabled`
 *
 * @param int $user_id
 *
 * @return bool
 */
function dokan_is_seller_enabled( $user_id ): bool {
    return apply_filters(
        'dokan_is_seller_enabled',
        'yes' === get_user_meta( $user_id, 'dokan_enable_selling', 'no' )
    );
}

/**
 * Check if the seller is trusted
 *
 * @param int $user_id
 *
 * @return bool
 */
function dokan_is_seller_trusted( $user_id ) {
    $publishing = get_user_meta( $user_id, 'dokan_publishing', true );

    return $publishing === 'yes';
}

/**
 * Get store page url of a seller
 *
 * @since 3.14.9 Added `$tab` optional parameter.
 *
 * @param int $user_id
 * @param string $tab Tab endpoint (Optional). Default is empty.
 *
 * @return string
 */
function dokan_get_store_url( $user_id, $tab = '' ) {
    if ( ! $user_id ) {
        return '';
    }

    $userdata         = get_userdata( $user_id );
    $user_nicename    = ( false !== $userdata ) ? $userdata->user_nicename : '';
    $custom_store_url = dokan_get_option( 'custom_store_url', 'dokan_general', 'store' );

    $path = '/' . $custom_store_url . '/' . $user_nicename . '/';
    if ( $tab ) {
        $tab  = untrailingslashit( trim( $tab, " \n\r\t\v\0/\\" ) );
        $path .= $tab;
        $path = trailingslashit( $path );
    }

    /**
     * Filter hook for the store URL before returning.
     *
     * @since 3.9.0
     * @since 3.14.9 Added `$tab` parameter
     *
     * @param string $store_url        The default store URL
     * @param string $custom_store_url The custom store URL
     * @param int    $user_id          The user ID for the store owner
     * @param string $tab              The tab endpoint. Default is empty.
     */
    return apply_filters( 'dokan_get_store_url', home_url( $path ), $custom_store_url, $user_id, $tab );
}

/**
 * Get current page URL.
 *
 * @since 3.9.1
 *
 * @return string
 */
function dokan_get_current_page_url() {
    global $wp;

    if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
        return add_query_arg( wc_clean( wp_unslash( $_SERVER['QUERY_STRING'] ) ), '', home_url( $wp->request ) );
    }

    return home_url( $wp->request );
}

/**
 * Check if current page is store review page
 *
 * @since 2.2
 *
 * @return bool
 */
function dokan_is_store_review_page() {
    return get_query_var( 'store_review' ) === 'true';
}

/**
 * Helper function for logging
 *
 * For valid levels, see `WC_Log_Levels` class
 *
 * Description of levels:
 *     'emergency': System is unusable.
 *     'alert': Action must be taken immediately.
 *     'critical': Critical conditions.
 *     'error': Error conditions.
 *     'warning': Warning conditions.
 *     'notice': Normal but significant condition.
 *     'info': Informational messages.
 *     'debug': Debug-level messages.
 *
 * @param string $message
 *
 * @return void
 */
function dokan_log( $message, $level = 'debug' ) {
    $logger  = wc_get_logger();
    $context = [ 'source' => 'dokan' ];

    $logger->log( $level, $message, $context );
}

/**
 * Filter WP Media Manager files if the current user is seller.
 *
 * Do not show other sellers images to a seller. He can see images only by him
 *
 * @param array $args
 *
 * @return array
 */
function dokan_media_uploader_restrict( $args ) {
    if ( current_user_can( 'manage_woocommerce' ) ) {
        return $args;
    }

    if ( current_user_can( 'dokandar' ) ) {
        $args['author'] = dokan_get_current_user_id();

        return $args;
    }

    return $args;
}

add_filter( 'ajax_query_attachments_args', 'dokan_media_uploader_restrict' );

/**
 * Get store info based on seller ID
 *
 * @param int $seller_id
 *
 * @return array
 */
function dokan_get_store_info( $seller_id ) {
    return dokan()->vendor->get( $seller_id )->get_shop_info();
}

/**
 * Get tabs for showing in a single store page
 *
 * @since 2.2
 *
 * @param int $store_id
 *
 * @return array
 */
function dokan_get_store_tabs( $store_id ) {
    $tabs = [
        'products'             => [
            'title' => __( 'Products', 'dokan-lite' ),
            'url'   => dokan_get_store_url( $store_id ),
        ],
        'terms_and_conditions' => [
            'title' => __( 'Terms and Conditions', 'dokan-lite' ),
            'url'   => dokan_get_toc_url( $store_id ),
        ],
    ];

    return apply_filters( 'dokan_store_tabs', $tabs, $store_id );
}

/**
 * Get withdraw email method based on seller ID and type
 *
 * @param int    $seller_id
 * @param string $type
 *
 * @return string
 */
function dokan_get_seller_withdraw_mail( $seller_id, $type = 'paypal' ) {
    $info = dokan_get_store_info( $seller_id );

    if ( isset( $info['payment'][ $type ]['email'] ) ) {
        return $info['payment'][ $type ]['email'];
    }

    return false;
}

/**
 * Get seller bank details
 *
 * @param int $seller_id
 *
 * @return string
 */
function dokan_get_seller_bank_details( $seller_id ) {
    $info    = dokan_get_store_info( $seller_id );
    $payment = $info['payment']['bank'];
    $details = [];

    if ( isset( $payment['ac_name'] ) ) {
        // translators: 1) bank account name
        $details[] = sprintf( __( 'Account Name: %s', 'dokan-lite' ), $payment['ac_name'] );
    }

    if ( isset( $payment['ac_number'] ) ) {
        // translators: 1) bank account number
        $details[] = sprintf( __( 'Account Number: %s', 'dokan-lite' ), $payment['ac_number'] );
    }

    if ( isset( $payment['bank_name'] ) ) {
        // translators: 1) bank name
        $details[] = sprintf( __( 'Bank Name: %s', 'dokan-lite' ), $payment['bank_name'] );
    }

    if ( isset( $payment['bank_addr'] ) ) {
        // translators: 1)  bank address
        $details[] = sprintf( __( 'Address: %s', 'dokan-lite' ), $payment['bank_addr'] );
    }

    if ( isset( $payment['routing_number'] ) ) {
        // translators: 1) bank routing number
        $details[] = sprintf( __( 'Routing Number: %s', 'dokan-lite' ), $payment['routing_number'] );
    }

    if ( isset( $payment['iban'] ) ) {
        // translators: 1) bank iban
        $details[] = sprintf( __( 'IBAN: %s', 'dokan-lite' ), $payment['iban'] );
    }

    if ( isset( $payment['swift'] ) ) {
        // translators: 1) bank swift
        $details[] = sprintf( __( 'SWIFT: %s', 'dokan-lite' ), $payment['swift'] );
    }

    return nl2br( implode( "\n", $details ) );
}

/**
 * Get seller listing
 *
 * @param array $args
 *
 * @return array
 */
function dokan_get_sellers( $args = [] ) {
    $vendors    = dokan()->vendor;
    $all_vendor = wp_list_pluck( $vendors->get_vendors( $args ), 'data' );

    return [
        'users' => $all_vendor,
        'count' => $vendors->get_total(),
    ];
}

/**
 * Put data with post_date's into an array of times
 *
 * @param array  $data       array of your data
 * @param string $date_key   key for the 'date' field. e.g. 'post_date'
 * @param string $data_key   key for the data you are charting
 * @param int    $interval
 * @param int    $start_date timestamp
 * @param string $group_by
 *
 * @return array
 */
function dokan_prepare_chart_data( $data, $date_key, $data_key, $interval, $start_date, $group_by ) {
    $prepared_data = [];
    $start_date    = dokan_current_datetime()->setTimestamp( $start_date )->setTime( 0, 0, 0 );
    $now           = dokan_current_datetime()->modify( 'today' ); // so that we don't need to write dokan_current_datetime() everytime

    // get duration string
    $duration_str = 'day' === $group_by ? 'P1D' : 'P1M';
    // fix start date
    $start_date = 'day' !== $group_by ? $start_date->modify( 'first day of this month' ) : $start_date;

    $date_interval = new DateInterval( $duration_str );
    $date_range    = $interval > 0 ? new DatePeriod( $start_date, $date_interval, $interval ) : [ $start_date ];
    foreach ( $date_range as $date ) {
        $time = $date->getTimestamp() . '000';
        if ( ! isset( $prepared_data[ $time ] ) ) {
            // Ensure all days (or months) have values first in this range
            $prepared_data[ $time ] = [ esc_js( $time ), 0 ];
        }
    }

    foreach ( $data as $d ) {
        switch ( $group_by ) {
            case 'day':
                //modify() can return zero
                $time = strtotime( $d->$date_key ) ? (string) $now->modify( $d->$date_key )->setTime( 0, 0, 0 )->getTimestamp() : (string) $now->getTimestamp();
                $time .= '000';
                break;

            default:
                $time = strtotime( $d->$date_key ) ? (string) $now->modify( $d->$date_key )->modify( 'first day of this month' )->setTime( 0, 0, 0 )->getTimestamp() : (string) $now->getTimestamp();
                $time .= '000';
                break;
        }

        if ( ! isset( $prepared_data[ $time ] ) ) {
            continue;
        }

        if ( $data_key ) {
            $prepared_data[ $time ][1] += $d->$data_key;
        } else {
            ++$prepared_data[ $time ][1];
        }
    }

    return $prepared_data;
}

/**
 * Disable selling capability by default once a seller is registered
 *
 * @param int $user_id
 */
function dokan_admin_user_register( $user_id ) {
    $user = new WP_User( $user_id );
    $role = reset( $user->roles );

    if ( $role === 'seller' ) {
        $enabled = 'automatically' === dokan_get_container()->get( \WeDevs\Dokan\Utilities\AdminSettings::class )->get_new_seller_enable_selling_status();
        update_user_meta( $user_id, 'dokan_enable_selling', $enabled ? 'yes' : 'no' );
    }
}

add_action( 'user_register', 'dokan_admin_user_register' );

/**
 * Get percentage based owo two numeric data
 *
 * @param int $this_period
 * @param int $last_period
 *
 * @return array
 */
function dokan_get_percentage_of( $this_period = 0, $last_period = 0 ) {
    $parcent     = 0;
    $this_period = intval( $this_period );
    $last_period = intval( $last_period );

    if ( ( 0 === $this_period && 0 === $last_period ) || $this_period === $last_period ) {
        $class = 'up';
    } elseif ( 0 === $this_period ) {
        $parcent = $last_period * 100;
        $class   = 'down';
    } elseif ( 0 === $last_period ) {
        $parcent = $this_period * 100;
        $class   = 'up';
    } elseif ( $this_period > $last_period ) {
        $parcent = ( $this_period - $last_period ) / $last_period * 100;
        $class   = 'up';
    } elseif ( $this_period < $last_period ) {
        $parcent = ( $last_period - $this_period ) / $last_period * 100;
        $class   = 'down';
    }

    $parcent = round( $parcent, 2 );

    return [
        'parcent' => $parcent,
        'class'   => $class,
    ];
}

/**
 * Get seller count based on enable, disabled sellers and time period
 *
 * @param string $from
 * @param string $to
 *
 * @return array
 */
function dokan_get_seller_count( $from = null, $to = null ) {
    $now              = dokan_current_datetime();
    $inactive_sellers = dokan_get_sellers(
        [
            'number' => - 1,
            'status' => 'pending',
        ]
    );

    $active_sellers = dokan_get_sellers(
        [
            'number' => - 1,
        ]
    );

    $this_month = dokan_get_sellers(
        [
            'date_query' => [
                [
                    'year'  => $now->format( 'Y' ),
                    'month' => $now->format( 'm' ),
                ],
            ],
        ]
    );

    $last_month = dokan_get_sellers(
        [
            'date_query' => [
                [
                    'year'  => $now->modify( 'last month' )->format( 'Y' ),
                    'month' => $now->modify( 'last month' )->format( 'm' ),
                ],
            ],
        ]
    );

    if ( $from && $to ) {
        $prepared_date = dokan_prepare_date_query( $from, $to );

        $this_period = dokan_get_sellers(
            [
                'date_query' => [
                    [
                        'after'  => [
                            'year'  => $prepared_date['from_year'],
                            'month' => $prepared_date['from_month'],
                            'day'   => $prepared_date['from_day'],
                        ],
                        'before' => [
                            'year'  => $prepared_date['to_year'],
                            'month' => $prepared_date['to_month'],
                            'day'   => $prepared_date['to_day'],
                        ],
                    ],
                ],
            ]
        );

        $last_period = dokan_get_sellers(
            [
                'date_query' => [
                    [
                        'after'  => [
                            'year'  => $prepared_date['last_from_year'],
                            'month' => $prepared_date['last_from_month'],
                            'day'   => $prepared_date['last_from_day'],
                        ],
                        'before' => [
                            'year'  => $prepared_date['last_to_year'],
                            'month' => $prepared_date['last_to_month'],
                            'day'   => $prepared_date['last_to_day'],
                        ],
                    ],
                ],
            ]
        );

        $vendor_parcent = dokan_get_percentage_of( $this_period['count'], $last_period['count'] );
    } else {
        $vendor_parcent = dokan_get_percentage_of( $this_month['count'], $last_month['count'] );
    }

    return [
        'inactive'    => $inactive_sellers['count'],
        'active'      => $active_sellers['count'],
        'this_month'  => $this_month['count'],
        'last_month'  => $last_month['count'],
        'this_period' => $from && $to ? $this_period['count'] : null,
        'class'       => $vendor_parcent['class'],
        'parcent'     => $vendor_parcent['parcent'],
    ];
}

/**
 * Get product count of this month and last month with percentage
 *
 * @param string $from
 * @param string $to
 *
 * @return array
 */
function dokan_get_product_count( $from = null, $to = null, $seller_id = null ) {
    $this_month_posts = dokan()->product->all(
        [
            'date_query' => [
                [
                    'year'  => dokan_current_datetime()->format( 'Y' ),
                    'month' => dokan_current_datetime()->format( 'm' ),
                ],
            ],
            'author'     => $seller_id ? $seller_id : '',
            'fields'     => 'ids',
        ]
    );

    $last_month_posts = dokan()->product->all(
        [
            'date_query' => [
                [
                    'year'  => dokan_current_datetime()->modify( 'last month' )->format( 'Y' ),
                    'month' => dokan_current_datetime()->modify( 'last month' )->format( 'm' ),
                ],
            ],
            'author'     => $seller_id ? $seller_id : '',
            'fields'     => 'ids',
        ]
    );

    if ( $from && $to ) {
        $prepared_date = dokan_prepare_date_query( $from, $to );

        $this_period = dokan()->product->all(
            [
                'date_query' => [
                    [
                        'after'  => [
                            'year'  => $prepared_date['from_year'],
                            'month' => $prepared_date['from_month'],
                            'day'   => $prepared_date['from_day'],
                        ],
                        'before' => [
                            'year'  => $prepared_date['to_year'],
                            'month' => $prepared_date['to_month'],
                            'day'   => $prepared_date['to_day'],
                        ],
                    ],
                ],
                'author'     => $seller_id ? $seller_id : '',
                'fields'     => 'ids',
            ]
        );

        $last_period = dokan()->product->all(
            [
                'date_query' => [
                    [
                        'after'  => [
                            'year'  => $prepared_date['last_from_year'],
                            'month' => $prepared_date['last_from_month'],
                            'day'   => $prepared_date['last_from_day'],
                        ],
                        'before' => [
                            'year'  => $prepared_date['last_to_year'],
                            'month' => $prepared_date['last_to_month'],
                            'day'   => $prepared_date['last_to_day'],
                        ],
                    ],
                ],
                'author'     => $seller_id ? $seller_id : '',
                'fields'     => 'ids',
            ]
        );

        $product_parcent = dokan_get_percentage_of( $this_period->found_posts, $last_period->found_posts );
    } else {
        $product_parcent = dokan_get_percentage_of( $this_month_posts->found_posts, $last_month_posts->found_posts );
    }

    return [
        'this_month'  => $this_month_posts->found_posts,
        'last_month'  => $last_month_posts->found_posts,
        'this_period' => $from && $to ? $this_period->found_posts : null,
        'class'       => $product_parcent['class'],
        'parcent'     => $product_parcent['parcent'],
    ];
}

/**
 * Dokan prepare date query
 *
 * @param string $from
 * @param string $to
 *
 * @return array
 */
function dokan_prepare_date_query( $from, $to ) {
    if ( ! $from || ! $to ) {
        return [];
    }

    $from_date     = date_create( $from );
    $raw_from_date = date_create( $from );
    $to_date       = date_create( $to );
    $raw_to_date   = date_create( $to );

    if ( ! $from_date || ! $to_date ) {
        wp_send_json( __( 'Date is not valid', 'dokan-lite' ) );
    }

    $from_year  = $from_date->format( 'Y' );
    $from_month = $from_date->format( 'm' );
    $from_day   = $from_date->format( 'd' );

    $to_year  = $to_date->format( 'Y' );
    $to_month = $to_date->format( 'm' );
    $to_day   = $to_date->format( 'd' );

    $date_diff      = date_diff( $from_date, $to_date );
    $last_from_date = $from_date->sub( $date_diff );
    $last_to_date   = $to_date->sub( $date_diff );

    $last_from_year  = $last_from_date->format( 'Y' );
    $last_from_month = $last_from_date->format( 'm' );
    $last_from_day   = $last_from_date->format( 'd' );

    $last_to_year  = $last_to_date->format( 'Y' );
    $last_to_month = $last_to_date->format( 'm' );
    $last_to_day   = $last_to_date->format( 'd' );

    $prepared_data = [
        'from_year'           => $from_year,
        'from_month'          => $from_month,
        'from_day'            => $from_day,
        'to_year'             => $to_year,
        'to_month'            => $to_month,
        'to_day'              => $to_day,
        'from_full_date'      => $raw_from_date->format( 'Y-m-d' ),
        'to_full_date'        => $raw_to_date->format( 'Y-m-d' ),
        'last_from_year'      => $last_from_year,
        'last_from_month'     => $last_from_month,
        'last_from_day'       => $last_from_day,
        'last_from_full_date' => $last_from_date->format( 'Y-m-d' ),
        'last_to_year'        => $last_to_year,
        'last_to_month'       => $last_to_month,
        'last_to_day'         => $last_to_day,
        'last_to_full_date'   => $last_to_date->format( 'Y-m-d' ),
    ];

    return $prepared_data;
}

/**
 * Get seles count based on this month and last month
 *
 * @global WPDB $wpdb
 *
 * @return array
 */
function dokan_get_sales_count( $from = null, $to = null, $seller_id = 0 ) {
    // get current month report
    $this_month_report_data = dokan_admin_report_data( 'day', '', '', '', $seller_id );

    $this_month_order_total   = 0;
    $this_month_earning_total = 0;
    $this_month_total_orders  = 0;
    // get current time
    $now = dokan_current_datetime();

    if ( $this_month_report_data ) {
        foreach ( $this_month_report_data as $row ) {
            $this_month_order_total   += $row->order_total;
            $this_month_earning_total += $row->earning;
            $this_month_total_orders  += $row->total_orders;
        }
    }

    // get last month report
    $last_month_report_data = dokan_admin_report_data(
        'day',
        '',
        $now->modify( 'first day of previous month' )->format( 'Y-m-d' ),
        $now->modify( 'last day of previous month' )->format( 'Y-m-d' ),
        $seller_id
    );

    $last_month_order_total   = 0;
    $last_month_earning_total = 0;
    $last_month_total_orders  = 0;

    if ( $last_month_report_data ) {
        foreach ( $last_month_report_data as $row ) {
            $last_month_order_total   += $row->order_total;
            $last_month_earning_total += $row->earning;
            $last_month_total_orders  += $row->total_orders;
        }
    }

    if ( $from && $to ) {
        $date             = dokan_prepare_date_query( $from, $to );
        $this_period_data = dokan_admin_report_data( 'day', $date['from_year'], $date['from_full_date'], $date['to_full_date'], $seller_id );
        $last_period_data = dokan_admin_report_data( 'day', $date['last_from_year'], $date['last_from_full_date'], $date['last_to_full_date'], $seller_id );

        $this_period_order_total   = 0;
        $this_period_earning_total = 0;
        $this_period_total_orders  = 0;
        $last_period_order_total   = 0;
        $last_period_earning_total = 0;
        $last_period_total_orders  = 0;

        if ( $this_period_data ) {
            foreach ( $this_period_data as $row ) {
                $this_period_order_total   += $row->order_total;
                $this_period_earning_total += $row->earning;
                $this_period_total_orders  += $row->total_orders;
            }
        }

        if ( $last_period_data ) {
            foreach ( $last_period_data as $row ) {
                $last_period_order_total   += $row->order_total;
                $last_period_earning_total += $row->earning;
                $last_period_total_orders  += $row->total_orders;
            }
        }

        $sale_percentage    = dokan_get_percentage_of( $this_period_order_total, $last_period_order_total );
        $earning_percentage = dokan_get_percentage_of( $this_period_earning_total, $last_period_earning_total );
        $order_percentage   = dokan_get_percentage_of( $this_period_total_orders, $last_period_total_orders );
    } else {
        $sale_percentage    = dokan_get_percentage_of( $this_month_order_total, $last_month_order_total );
        $earning_percentage = dokan_get_percentage_of( $this_month_earning_total, $last_month_earning_total );
        $order_percentage   = dokan_get_percentage_of( $this_month_total_orders, $last_month_total_orders );
    }

    $data = [
        'sales'   => [
            'this_month'  => $this_month_order_total,
            'last_month'  => $last_month_order_total,
            'this_period' => $from && $to ? $this_period_order_total : null,
            'class'       => $sale_percentage['class'],
            'parcent'     => $sale_percentage['parcent'],
        ],
        'orders'  => [
            'this_month'  => $this_month_total_orders,
            'last_month'  => $last_month_total_orders,
            'this_period' => $from && $to ? $this_period_total_orders : null,
            'class'       => $order_percentage['class'],
            'parcent'     => $order_percentage['parcent'],
        ],
        'earning' => [
            'this_month'  => $this_month_earning_total,
            'last_month'  => $last_month_earning_total,
            'this_period' => $from && $to ? $this_period_earning_total : null,
            'class'       => $earning_percentage['class'],
            'parcent'     => $earning_percentage['parcent'],
        ],
    ];

    return $data;
}

/**
 * Prevent sellers and customers from seeing the admin bar
 *
 * @param bool $show_admin_bar
 *
 * @return bool
 */
function dokan_disable_admin_bar( $show_admin_bar ) {
    global $current_user;

    if ( $current_user->ID !== 0 ) {
        $role = reset( $current_user->roles );
        $block_admin_access = dokan_get_option( 'admin_access', 'dokan_general', 'on' );
        if ( OrderUtil::is_hpos_enabled() ) {
            $block_admin_access = 'on';
        }

        if ( $block_admin_access === 'on' ) {
            if ( in_array( $role, [ 'seller', 'customer', 'vendor_staff' ], true ) ) {
                return false;
            }
        }
    }

    return $show_admin_bar;
}

add_filter( 'show_admin_bar', 'dokan_disable_admin_bar' );

/**
 * Filter products of current user
 *
 * @since 2.7.3
 *
 * @param object $query
 *
 * @return object $query
 */
function dokan_filter_product_for_current_vendor( $query ) {
    if ( current_user_can( 'manage_woocommerce' ) ) {
        return $query;
    }

    if ( ! isset( $query->query_vars['post_type'] ) ) {
        return $query;
    }

    if ( is_admin() && $query->is_main_query() && $query->query_vars['post_type'] === 'product' ) {
        $query->set( 'author', get_current_user_id() );
    }

    return $query;
}

add_filter( 'pre_get_posts', 'dokan_filter_product_for_current_vendor' );

/**
 * Remove sellerdiv metabox when a seller can access the backend
 *
 * @since 2.7.8
 *
 * @return void
 */
function dokan_remove_sellerdiv_metabox() {
    if ( current_user_can( 'manage_woocommerce' ) ) {
        return;
    }

    if ( is_admin() && get_post_type() === 'product' && ! defined( 'DOING_AJAX' ) ) {
        remove_meta_box( 'sellerdiv', 'product', 'normal' );
    }
}

add_action( 'do_meta_boxes', 'dokan_remove_sellerdiv_metabox' );

/**
 * Human readable number format.
 *
 * Shortens the number by dividing 1000
 *
 * @param float|int $number
 *
 * @return float|int|string
 */
function dokan_number_format( $number ) {
    $threshold = 10000;

    if ( $number > $threshold ) {
        return number_format( $number / 1000, 0, '.', '' ) . ' K';
    }

    return $number;
}

/**
 * Get coupon edit url
 *
 * @param int    $coupon_id
 * @param string $coupon_page
 *
 * @return string
 */
function dokan_get_coupon_edit_url( $coupon_id, $coupon_page = '' ) {
    if ( ! $coupon_page ) {
        $coupon_page = dokan_get_page_url( 'coupons' );
    }

    $edit_url = wp_nonce_url(
        add_query_arg(
            [
                'post'   => $coupon_id,
                'action' => 'edit',
                'view'   => 'add_coupons',
            ],
            $coupon_page
        ),
        '_coupon_nonce',
        'coupon_nonce_url'
    );

    return $edit_url;
}

/**
 * Filter `get_avatar_url` to retrieve image url from dokan profile settings
 * called by `get_avatar_url()` as well as `get_avatar()`
 *
 * @since 2.7.0
 *
 * @param string $url         avatar url
 * @param mixed  $id_or_email userdata or user_id or user_email
 * @param array  $args        arguments
 *
 * @return string maybe modified url
 */
function dokan_get_avatar_url( $url, $id_or_email, $args ) {
    if ( is_numeric( $id_or_email ) ) {
        $user = get_user_by( 'id', $id_or_email );
    } elseif ( is_object( $id_or_email ) ) {
        if ( (int) $id_or_email->user_id !== 0 ) {
            $user = get_user_by( 'id', $id_or_email->user_id );
        } else {
            return $url;
        }
    } else {
        $user = get_user_by( 'email', $id_or_email );
    }

    if ( ! $user ) {
        return $url;
    }

    $vendor = dokan()->vendor;

    if ( ! $vendor ) {
        return $url;
    }

    $vendor = $vendor->get( $user->ID );
    if ( ! $vendor->is_vendor() ) {
        return $url;
    }

    $gravatar_id = $vendor->get_avatar_id();

    if ( ! $gravatar_id ) {
        return $url;
    }

    $dokan_avatar_url = wp_get_attachment_thumb_url( $gravatar_id );

    if ( empty( $dokan_avatar_url ) ) {
        return $url;
    }

    return esc_url( $dokan_avatar_url );
}

add_filter( 'get_avatar_url', 'dokan_get_avatar_url', 99, 3 );

/**
 * Get navigation url for the dokan dashboard
 *
 * @param string $name    endpoint name
 * @param bool   $new_url if true, it will return the new url format
 *
 * @return string url
 */
function dokan_get_navigation_url( $name = '', $new_url = false ) {
    $page_id = (int) dokan_get_option( 'dashboard', 'dokan_pages', 0 );

    if ( ! $page_id ) {
        return '';
    }

    $url = rtrim( get_permalink( $page_id ), '/' ) . '/';

    if ( ! empty( $name ) && ! $new_url ) {
        $url = dokan_add_subpage_to_url( $url, $name . '/' );
    }

    if ( $new_url ) {
        $url = dokan_add_subpage_to_url( $url, 'new/' );
        $url = $url . '#' . $name . '/';
    }

    return apply_filters( 'dokan_get_navigation_url', esc_url( $url ), $name, $new_url );
}

/**
 * Generate country dropdwon
 *
 * @param array  $options
 * @param string $selected
 * @param bool   $everywhere
 */
function dokan_country_dropdown( $options, $selected = '', $everywhere = false ) {
    printf( '<option value="">%s</option>', esc_html__( '- Select a location -', 'dokan-lite' ) );

    if ( $everywhere ) {
        echo '<optgroup label="--------------------------">';
        printf( '<option value="everywhere"%s>%s</option>', selected( $selected, 'everywhere', true ), esc_html__( 'Everywhere Else', 'dokan-lite' ) );
        echo '</optgroup>';
    }

    echo '<optgroup label="------------------------------">';

    foreach ( $options as $key => $value ) {
        printf( '<option value="%s"%s>%s</option>', esc_attr( $key ), selected( $selected, $key, true ), esc_html( $value ) );
    }
    echo '</optgroup>';
}

/**
 * Generate country dropdwon
 *
 * @param array  $options
 * @param string $selected
 * @param bool   $everywhere
 */
function dokan_state_dropdown( $options, $selected = '', $everywhere = false ) {
    printf( '<option value="">%s</option>', esc_html__( '- Select a State -', 'dokan-lite' ) );

    if ( $everywhere ) {
        echo '<optgroup label="--------------------------">';
        printf( '<option value="everywhere" %s>%s</option>', selected( $selected, 'everywhere', true ), esc_html__( 'Everywhere Else', 'dokan-lite' ) );
        echo '</optgroup>';
    }

    echo '<optgroup label="------------------------------">';

    foreach ( $options as $key => $value ) {
        printf( '<option value="%s" %s>%s</option>', esc_attr( $key ), selected( $selected, $key, true ), esc_html( $value ) );
    }
    echo '</optgroup>';
}

/**
 * Shupping Processing time dropdown options
 *
 * @return array
 */
function dokan_get_shipping_processing_times() {
    $times = [
        ''  => __( 'Ready to ship in...', 'dokan-lite' ),
        '1' => __( '1 business day', 'dokan-lite' ),
        '2' => __( '1-2 business days', 'dokan-lite' ),
        '3' => __( '1-3 business days', 'dokan-lite' ),
        '4' => __( '3-5 business days', 'dokan-lite' ),
        '5' => __( '1-2 weeks', 'dokan-lite' ),
        '6' => __( '2-3 weeks', 'dokan-lite' ),
        '7' => __( '3-4 weeks', 'dokan-lite' ),
        '8' => __( '4-6 weeks', 'dokan-lite' ),
        '9' => __( '6-8 weeks', 'dokan-lite' ),
    ];

    return apply_filters( 'dokan_shipping_processing_times', $times );
}

/**
 * Get a single processing time string
 *
 * @param string $index
 *
 * @return string
 */
function dokan_get_processing_time_value( $index ) {
    $times = dokan_get_shipping_processing_times();

    if ( isset( $times[ $index ] ) ) {
        return $times[ $index ];
    }
}

/**
 * Send email to seller and admin when there is no product in stock or low stock
 *
 * @since 2.8.0
 *
 * @param string $recipient recipients email
 * @param WC_Product $product
 *
 * @return string recipient emails
 */
function dokan_wc_email_recipient_add_seller_no_stock( $recipient, $product ) {
    $product_id   = $product->get_id();
    $seller_id    = get_post_field( 'post_author', $product_id );
    $seller_email = dokan()->vendor->get( $seller_id )->get_email();

    return $recipient . ', ' . $seller_email;
}

add_filter( 'woocommerce_email_recipient_no_stock', 'dokan_wc_email_recipient_add_seller_no_stock', 10, 2 );
add_filter( 'woocommerce_email_recipient_low_stock', 'dokan_wc_email_recipient_add_seller_no_stock', 10, 2 );

/**
 * Get all the months of products of a vendor.
 *
 * @since DOKAN_LITE
 *
 * @param int $user_id
 *
 * @return object
 */
function dokan_get_products_listing_months_for_vendor( $user_id ) {
    global $wpdb, $wp_locale;

    $months = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->prepare(
            "SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
            FROM $wpdb->posts
            WHERE post_type = 'product'
            AND post_author = %d
            ORDER BY post_date DESC",
            $user_id
        )
    );

    /**
     * Filter the 'Months' drop-down results.
     *
     * @since 2.1
     *
     * @param object $months the months drop-down query results
     */
    return apply_filters( 'months_dropdown_results', $months, 'product' );
}

/**
 * Display a monthly dropdown for filtering product listing on seller dashboard
 *
 * @since 2.1
 *
 * @param int $user_id
 */
function dokan_product_listing_filter_months_dropdown( $user_id ) {
    global $wp_locale;

    $months      = dokan_get_products_listing_months_for_vendor( $user_id );
    $month_count = count( $months );

    if ( ! $month_count || ( 1 === $month_count && 0 === (int) $months[0]->month ) ) {
        return;
    }

    // get default date
    $date = 0;
    // get date from url
    if ( isset( $_GET['_product_listing_filter_nonce'], $_GET['date'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_product_listing_filter_nonce'] ) ), 'product_listing_filter' ) ) {
        $date = intval( wp_unslash( $_GET['date'] ) );
    }
    ?>
    <select name="date" id="filter-by-date" class="dokan-form-control">
        <option<?php selected( $date, 0 ); ?> value="0"><?php esc_html_e( 'All dates', 'dokan-lite' ); ?></option>
        <?php
        foreach ( $months as $arc_row ) {
            if ( 0 === $arc_row->year ) {
                continue;
            }

            $month = zeroise( $arc_row->month, 2 );
            $year  = $arc_row->year;

            printf(
                "<option %s value='%s' >%s</option>\n",
                selected( $date, $year . $month, false ),
                esc_attr( $year . $month ),
                /* translators: 1: month name, 2: 4-digit year */
                sprintf( esc_html__( '%1$s %2$d', 'dokan-lite' ), esc_html( $wp_locale->get_month( $month ) ), esc_html( $year ) ) // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
            );
        }
        ?>
    </select>
    <?php
}

/**
 * Display form for filtering product listing on seller dashboard
 *
 * @since 2.1
 */
function dokan_product_listing_filter() {
    $template_args = [
        'product_types'       => apply_filters( 'dokan_product_types', [ 'simple' => __( 'Simple', 'dokan-lite' ) ] ),
        'product_cat'         => -1,
        'product_brand'       => -1,
        'product_search_name' => '',
        'date'                => '',
        'product_type'        => '',
        'filter_by_other'     => '',
        'post_status'         => 'all',
    ];

    if ( isset( $_GET['_product_listing_filter_nonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_product_listing_filter_nonce'] ) ), 'product_listing_filter' ) ) {
        $template_args['product_cat']         = ! empty( $_GET['product_cat'] ) ? intval( wp_unslash( $_GET['product_cat'] ) ) : -1;
        $template_args['product_brand']       = ! empty( $_GET['product_brand'] ) ? intval( wp_unslash( $_GET['product_brand'] ) ) : -1;
        $template_args['product_search_name'] = ! empty( $_GET['product_search_name'] ) ? sanitize_text_field( wp_unslash( $_GET['product_search_name'] ) ) : '';
        $template_args['date']                = ! empty( $_GET['date'] ) ? intval( wp_unslash( $_GET['date'] ) ) : '';
        $template_args['product_type']        = ! empty( $_GET['product_type'] ) ? sanitize_text_field( wp_unslash( $_GET['product_type'] ) ) : '';
        $template_args['filter_by_other']     = ! empty( $_GET['filter_by_other'] ) ? sanitize_text_field( wp_unslash( $_GET['filter_by_other'] ) ) : '';
        $template_args['post_status']         = ! empty( $_GET['post_status'] ) ? sanitize_text_field( wp_unslash( $_GET['post_status'] ) ) : 'all';
    }

    dokan_get_template_part( 'products/listing-filter', '', apply_filters( 'dokan_product_listing_filter_args', $template_args ) );
}

/**
 * Search by SKU or ID for seller dashboard product listings.
 *
 * @param string $where
 *
 * @return string
 */
function dokan_product_search_by_sku( $where ) {
    // nonce checking
    if ( ! isset( $_GET['_product_listing_filter_nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_product_listing_filter_nonce'] ) ), 'product_listing_filter' ) ) {
        return $where;
    }

    if ( empty( $_GET['product_search_name'] ) ) {
        return $where;
    }

    global $wpdb;

    $search_ids = [];
    $terms      = explode( ',', wc_clean( wp_unslash( $_GET['product_search_name'] ) ) );

    foreach ( $terms as $term ) {
        if ( is_numeric( $term ) ) {
            $search_ids[] = $term;
        }

        // Attempt to get a SKU
        $wild = '%';
        $find = wc_clean( $term );
        $like = $wild . $wpdb->esc_like( $find ) . $wild;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $sku_to_id = $wpdb->get_col( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_sku' AND meta_value LIKE %s", $like ) );

        if ( $sku_to_id && count( $sku_to_id ) > 0 ) {
            $search_ids = array_merge( $search_ids, $sku_to_id );
        }
    }

    $search_ids = array_filter( array_map( 'absint', $search_ids ) );

    if ( count( $search_ids ) > 0 ) {
        $where = str_replace( ')))', ") OR ({$wpdb->posts}.ID IN (" . implode( ',', $search_ids ) . '))))', $where );
    }

    return $where;
}

add_filter( 'posts_search', 'dokan_product_search_by_sku' );

/**
 * Dokan Social Profile fields
 *
 * @since 2.2
 *
 * @return array
 */
function dokan_get_social_profile_fields() {
    $fields = [
        'fb'        => [
            'icon'  => 'facebook-square',
            'title' => __( 'Facebook', 'dokan-lite' ),
        ],
        'twitter'   => [
            'icon'  => 'fa-brands fa-square-x-twitter',
            'title' => __( 'X', 'dokan-lite' ),
        ],
        'pinterest' => [
            'icon'  => 'pinterest-square',
            'title' => __( 'Pinterest', 'dokan-lite' ),
        ],
        'linkedin'  => [
            'icon'  => 'linkedin',
            'title' => __( 'LinkedIn', 'dokan-lite' ),
        ],
        'youtube'   => [
            'icon'  => 'youtube-square',
            'title' => __( 'Youtube', 'dokan-lite' ),
        ],
        'tiktok'    => [
            'icon'  => 'tiktok',
            'title' => __( 'TikTok', 'dokan-lite' ),
        ],
        'instagram' => [
            'icon'  => 'instagram',
            'title' => __( 'Instagram', 'dokan-lite' ),
        ],
        'flickr'    => [
            'icon'  => 'flickr',
            'title' => __( 'Flickr', 'dokan-lite' ),
        ],
        'threads'   => [
            'icon'  => 'fa-brands fa-threads',
            'title' => __( 'Threads', 'dokan-lite' ),
        ],
    ];

    return apply_filters( 'dokan_profile_social_fields', $fields );
}

/**
 * Generate Address fields form for seller
 *
 * @since 2.3
 *
 * @param bool $verified verified
 * @param bool $required required
 *
 * @return void
 */
function dokan_seller_address_fields( $verified = false, $required = false ) {
    $disabled = $verified ? 'disabled' : '';

    /**
     * Filter the seller Address fields
     *
     * @since 2.2
     *
     * @param array $dokan_seller_address
     */
    $seller_address_fields = apply_filters(
        'dokan_seller_address_fields', [
            'street_1' => [
                'required' => $required ? 1 : 0,
            ],
            'street_2' => [
                'required' => 0,
            ],
            'city'     => [
                'required' => $required ? 1 : 0,
            ],
            'zip'      => [
                'required' => $required ? 1 : 0,
            ],
            'country'  => [
                'required' => 1,
            ],
            'state'    => [
                'required' => 0,
            ],
        ]
    );

    $profile_info = dokan_get_store_info( dokan_get_current_user_id() );

    dokan_get_template_part(
        'settings/address-form', '', [
            'disabled'              => $disabled,
            'seller_address_fields' => $seller_address_fields,
            'profile_info'          => $profile_info,
        ]
    );
}

/**
 * Generate Address string | array for given seller id or current user
 *
 * @since 2.3
 *
 * @param int $seller_id, defaults to current_user_id
 * @param bool $get_array, if true returns array instead of string
 *
 * @return string|array Address | array Address
 */
function dokan_get_seller_address( $seller_id = 0, $get_array = false ) {
    if ( empty( $seller_id ) ) {
        $seller_id = dokan_get_current_user_id();
    }

    $profile_info = dokan_get_store_info( $seller_id );

    if ( isset( $profile_info['address'] ) ) {
        $address = $profile_info['address'];

        $country_obj = new WC_Countries();
        $countries   = $country_obj->countries;
        $states      = $country_obj->states;

        $street_1 = isset( $address['street_1'] ) ? $address['street_1'] : '';
        $street_2 = isset( $address['street_2'] ) ? $address['street_2'] : '';
        $city     = isset( $address['city'] ) ? $address['city'] : '';

        $zip          = isset( $address['zip'] ) ? $address['zip'] : '';
        $country_code = isset( $address['country'] ) ? $address['country'] : '';
        $state_code   = isset( $address['state'] ) ? ( $address['state'] === 'N/A' ) ? '' : $address['state'] : '';

        $country_name = isset( $countries[ $country_code ] ) ? $countries[ $country_code ] : '';
        $state_name   = isset( $states[ $country_code ][ $state_code ] ) ? $states[ $country_code ][ $state_code ] : $state_code;
    } else {
        return 'N/A';
    }

    if ( $get_array === true ) {
        $address = [
            'street_1' => $street_1,
            'street_2' => $street_2,
            'city'     => $city,
            'zip'      => $zip,
            'country'  => $country_name,
            'state'    => isset( $states[ $country_code ][ $state_code ] ) ? $states[ $country_code ][ $state_code ] : $state_code,
        ];

        return apply_filters( 'dokan_get_seller_address', $address, $profile_info );
    }

    $country           = new WC_Countries();
    $formatted_address = $country->get_formatted_address(
        [
            'address_1' => $street_1,
            'address_2' => $street_2,
            'city'      => $city,
            'postcode'  => $zip,
            'state'     => $state_code,
            'country'   => $country_code,
        ]
    );

    return apply_filters( 'dokan_get_seller_formatted_address', $formatted_address, $profile_info );
}

/**
 * Dokan get seller short formatted address
 *
 * @since  2.5.7
 *
 * @param int  $store_id
 * @param bool $line_break
 *
 * @return string
 */
function dokan_get_seller_short_address( $store_id, $line_break = true ) {
    $store_address     = dokan_get_seller_address( $store_id, true );
    $address_classes   = [
        'street_1',
        'street_2',
        'city',
        'state',
        'country',
    ];
    $short_address     = [];
    $formatted_address = '';

    if ( ! empty( $store_address['street_1'] ) && empty( $store_address['street_2'] ) ) {
        $short_address[] = "<span class='{$address_classes[0]}'> {$store_address['street_1']},</span>";
    } elseif ( empty( $store_address['street_1'] ) && ! empty( $store_address['street_2'] ) ) {
        $short_address[] = "<span class='{$address_classes[1]}'> {$store_address['street_2']},</span>";
    } elseif ( ! empty( $store_address['street_1'] ) && ! empty( $store_address['street_2'] ) ) {
        $short_address[] = "<span class='{$address_classes[0]} {$address_classes[1]}'> {$store_address['street_1']}, {$store_address['street_2']}</span>";
    }

    if ( ! empty( $store_address['city'] ) && ! empty( $store_address['city'] ) ) {
        $short_address[] = "<span class='{$address_classes[2]}'> {$store_address['city']},</span>";
    }

    if ( ! empty( $store_address['state'] ) && ! empty( $store_address['country'] ) ) {
        $short_address[] = "<span class='{$address_classes[3]}'> {$store_address['state']},</span><span class='{$address_classes[4]}'> {$store_address['country']} </span>";
    } elseif ( ! empty( $store_address['country'] ) ) {
        $short_address[] = "<span class='{$address_classes[4]}'> {$store_address['country']} </span>";
    }

    if ( ! empty( $short_address ) && $line_break ) {
        $formatted_address = implode( '<br>', $short_address );
    } else {
        $formatted_address = implode( ' ', $short_address );
    }

    return apply_filters( 'dokan_store_header_adress', $formatted_address, $store_address, $short_address );
}

/**
 * Get terms and conditions page
 *
 * @since 2.3
 *
 * @param int $store_id
 *
 * @return string
 */
function dokan_get_toc_url( $store_id ) {
    if ( ! $store_id ) {
        return '';
    }

    $store_info = dokan_get_store_info( $store_id );
    $tnc_enable = dokan_get_option( 'seller_enable_terms_and_conditions', 'dokan_general', 'off' );

    if ( ! ( isset( $store_info['enable_tnc'] ) && $store_info['enable_tnc'] === 'on' && $tnc_enable === 'on' ) ) {
        return '';
    }

    return apply_filters( 'dokan_get_toc_url', dokan_get_store_url( $store_id, 'toc' ) );
}

/**
 * Login Redirect
 *
 * @since 2.4
 *
 * @param string  $redirect_to [url]
 * @param WP_User $user
 *
 * @return string [url]
 */
function dokan_after_login_redirect( $redirect_to, $user ) {
    // get the redirect url from $_GET
    if ( ! empty( $_GET['redirect_to'] ) ) { // phpcs:ignore
        $redirect_to = esc_url( wp_unslash( $_GET['redirect_to'] ) ); // phpcs:ignore
    } elseif ( user_can( $user, 'dokandar' ) && wc_get_page_permalink( 'checkout' ) !== $redirect_to ) {
        $seller_dashboard = (int) dokan_get_option( 'dashboard', 'dokan_pages' );

        if ( $seller_dashboard !== - 1 ) {
            $redirect_to = get_permalink( $seller_dashboard );
        }
    }

    return $redirect_to;
}

add_filter( 'woocommerce_login_redirect', 'dokan_after_login_redirect', 1, 2 );

/**
 * Check if the post belongs to the given user
 *
 * @param int $post_id
 * @param int $user_id
 *
 * @return bool
 */
function dokan_is_valid_owner( $post_id, $user_id ) {
    $author = (int) get_post_field( 'post_author', $post_id );

    if ( $user_id === $author ) {
        return true;
    }

    return false;
}

add_action( 'wp', 'dokan_set_is_home_false_on_store' );

function dokan_set_is_home_false_on_store() {
    global $wp_query;

    if ( dokan_is_store_page() ) {
        $wp_query->is_home = false;
    }
}

/**
 * Register dokan store widget
 *
 * @return void
 */
function dokan_register_store_widget() {
    register_sidebar(
        apply_filters(
            'dokan_store_widget_args', [
                'name'          => __( 'Dokan Store Sidebar', 'dokan-lite' ),
                'id'            => 'sidebar-store',
                'before_widget' => '<aside id="%1$s" class="widget dokan-store-widget %2$s">',
                'after_widget'  => '</aside>',
                'before_title'  => '<h3 class="widget-title">',
                'after_title'   => '</h3>',
            ]
        )
    );
}

add_action( 'widgets_init', 'dokan_register_store_widget' );

/**
 * Calculate category wise commission for given product.
 *
 * @deprecated 3.14.0 Do Not Use This Function
 *
 * @since 2.6.8
 *
 * @param int $product_id
 *
 * @return int $commission_rate
 */
function dokan_get_category_wise_seller_commission( $product_id, $category_id = 0 ) {
    wc_deprecated_function( __FUNCTION__, '3.14.0' );

    return 0;
}

/**
 * Calculate category wise commission type for given product.
 *
 * @deprecated 3.14.0 Do Not Use This Function
 *
 * @since 2.6.9
 *
 * @param int $product_id
 *
 * @return int $commission_rate
 */
function dokan_get_category_wise_seller_commission_type( $product_id, $category_id = 0 ) {
    wc_deprecated_function( __FUNCTION__, '3.14.0' );

    return '';
}

/**
 * Get seller earning for a given product
 *
 * @since 2.6.9
 *
 * @param int $product_id
 * @param int $seller_id
 *
 * @deprecated 2.9.11
 *
 * @return float $earning | zero on failure or no price
 */
function dokan_get_earning_by_product( $product_id, $seller_id ) {
    wc_deprecated_function( 'dokan_get_earning_by_product', '2.9.21', 'dokan()->comission->get_earning_by_product()' );

    return dokan()->commission->get_earning_by_product( $product_id );
}

add_action( 'delete_user', 'dokan_delete_user_details', 10, 2 );

/**
 * Delete user's details when the user is deleted
 *
 * @since 2.6.9
 *
 * @param int $user_id , int $reassign
 *
 * @return void
 */
function dokan_delete_user_details( $user_id, $reassign ) {
    if ( ! dokan_is_user_seller( $user_id ) ) {
        return;
    }

    if ( is_null( $reassign ) ) {
        $args = [
            'numberposts' => - 1,
            'post_type'   => 'any',
            'author'      => $user_id,
        ];

        // get all posts by this user
        $user_posts = get_posts( $args );

        if ( empty( $user_posts ) ) {
            return;
        }

        // delete all the posts
        foreach ( $user_posts as $user_post ) {
            wp_delete_post( $user_post->ID, true );
        }
    }
}

/**
 * Get a vendor
 *
 * @since 2.6.10
 *
 * @param int $vendor_id
 *
 * @return WeDevs\Dokan\Vendor\Vendor
 */
function dokan_get_vendor( $vendor_id = null ) {
    if ( ! $vendor_id ) {
        $vendor_id = wp_get_current_user();
    }

    return dokan()->vendor->get( $vendor_id );
}

/**
 * Get all cap related to seller
 *
 * @since 2.7.3
 *
 * @return array
 */
function dokan_get_all_caps() {
    $capabilities = [
        'overview' => [
            'dokan_view_sales_overview'        => __( 'View sales overview', 'dokan-lite' ),
            'dokan_view_sales_report_chart'    => __( 'View sales report chart', 'dokan-lite' ),
            'dokan_view_announcement'          => __( 'View announcement', 'dokan-lite' ),
            'dokan_view_order_report'          => __( 'View order report', 'dokan-lite' ),
            'dokan_view_review_reports'        => __( 'View review report', 'dokan-lite' ),
            'dokan_view_product_status_report' => __( 'View product status report', 'dokan-lite' ),
        ],
        'report'   => [
            'dokan_view_overview_report'    => __( 'View overview report', 'dokan-lite' ),
            'dokan_view_daily_sale_report'  => __( 'View daily sales report', 'dokan-lite' ),
            'dokan_view_top_selling_report' => __( 'View top selling report', 'dokan-lite' ),
            'dokan_view_top_earning_report' => __( 'View top earning report', 'dokan-lite' ),
            'dokan_view_statement_report'   => __( 'View statement report', 'dokan-lite' ),
        ],
        'order'    => [
            'dokan_view_order'        => __( 'View order', 'dokan-lite' ),
            'dokan_manage_order'      => __( 'Manage order', 'dokan-lite' ),
            'dokan_manage_order_note' => __( 'Manage order note', 'dokan-lite' ),
            'dokan_manage_refund'     => __( 'Manage refund', 'dokan-lite' ),
            'dokan_export_order'      => __( 'Export order', 'dokan-lite' ),
        ],
        'coupon'   => [
            'dokan_add_coupon'    => __( 'Add coupon', 'dokan-lite' ),
            'dokan_edit_coupon'   => __( 'Edit coupon', 'dokan-lite' ),
            'dokan_delete_coupon' => __( 'Delete coupon', 'dokan-lite' ),
        ],
        'review'   => [
            'dokan_view_reviews'   => __( 'View reviews', 'dokan-lite' ),
            'dokan_manage_reviews' => __( 'Manage reviews', 'dokan-lite' ),
        ],

        'withdraw' => [
            'dokan_manage_withdraw' => __( 'Manage withdraw', 'dokan-lite' ),
        ],
        'product'  => [
            'dokan_add_product'       => __( 'Add product', 'dokan-lite' ),
            'dokan_edit_product'      => __( 'Edit product', 'dokan-lite' ),
            'dokan_delete_product'    => __( 'Delete product', 'dokan-lite' ),
            'dokan_view_product'      => __( 'View product', 'dokan-lite' ),
            'dokan_duplicate_product' => __( 'Duplicate product', 'dokan-lite' ),
            'dokan_import_product'    => __( 'Import product', 'dokan-lite' ),
            'dokan_export_product'    => __( 'Export product', 'dokan-lite' ),
        ],
        'menu'     => [
            'dokan_view_overview_menu'       => __( 'View overview menu', 'dokan-lite' ),
            'dokan_view_product_menu'        => __( 'View product menu', 'dokan-lite' ),
            'dokan_view_order_menu'          => __( 'View order menu', 'dokan-lite' ),
            'dokan_view_coupon_menu'         => __( 'View coupon menu', 'dokan-lite' ),
            'dokan_view_report_menu'         => __( 'View report menu', 'dokan-lite' ),
            'dokan_view_review_menu'         => __( 'View review menu', 'dokan-lite' ),
            'dokan_view_withdraw_menu'       => __( 'View withdraw menu', 'dokan-lite' ),
            'dokan_view_store_settings_menu' => __( 'View store settings menu', 'dokan-lite' ),
            'dokan_view_store_payment_menu'  => __( 'View payment settings menu', 'dokan-lite' ),
            'dokan_view_store_shipping_menu' => __( 'View shipping settings menu', 'dokan-lite' ),
            'dokan_view_store_social_menu'   => __( 'View social settings menu', 'dokan-lite' ),
            'dokan_view_store_seo_menu'      => __( 'View seo settings menu', 'dokan-lite' ),
        ],
    ];

    return apply_filters( 'dokan_get_all_cap', $capabilities );
}

/**
 * Get translated capability
 *
 * @since 3.0.2
 *
 * @param string $cap
 *
 * @return string
 */
function dokan_get_all_cap_labels( $cap ) {
    $caps = apply_filters(
        'dokan_get_all_cap_labels', [
            'overview' => __( 'Overview', 'dokan-lite' ),
            'report'   => __( 'Report', 'dokan-lite' ),
            'order'    => __( 'Order', 'dokan-lite' ),
            'coupon'   => __( 'Coupon', 'dokan-lite' ),
            'review'   => __( 'Review', 'dokan-lite' ),
            'withdraw' => __( 'Withdraw', 'dokan-lite' ),
            'product'  => __( 'Product', 'dokan-lite' ),
            'menu'     => __( 'Menu', 'dokan-lite' ),
        ]
    );

    return ! empty( $caps[ $cap ] ) ? $caps[ $cap ] : '';
}

/**
 * Merge user defined arguments into defaults array.
 *
 * This function is similiar to WordPress wp_parse_args().
 * It's support multidimensional array.
 *
 * @param array $args
 * @param array $defaults optional
 *
 * @return array
 */
function dokan_parse_args( &$args, $defaults = [] ) {
    $args     = (array) $args;
    $defaults = (array) $defaults;
    $r        = $defaults;

    foreach ( $args as $k => &$v ) {
        if ( is_array( $v ) && isset( $r[ $k ] ) ) {
            $r[ $k ] = dokan_parse_args( $v, $r[ $k ] );
        } else {
            $r[ $k ] = $v;
        }
    }

    return $r;
}

function dokan_get_translations_for_plugin_domain( $domain, $language_dir = null ) {
    if ( $language_dir === null ) {
        $language_dir = DOKAN_DIR . '/languages/';
    }

    $get_site_lang         = is_admin() ? get_user_locale() : get_locale();
    $mo_file_name          = $domain . '-' . $get_site_lang;
    $plugin_language_dir   = WP_LANG_DIR . '/plugins/';
    $languages             = get_available_languages( $language_dir );
    $languages_in_lang_dir = get_available_languages( $plugin_language_dir );
    $translations          = [];

    if ( in_array( $mo_file_name, $languages_in_lang_dir, true ) && file_exists( $plugin_language_dir . $mo_file_name . '.mo' ) ) {
        $mo = new MO();

        if ( $mo->import_from_file( $plugin_language_dir . $mo_file_name . '.mo' ) ) {
            $translations = $mo->entries;
        }
    } elseif ( in_array( $mo_file_name, $languages, true ) && file_exists( $language_dir . $mo_file_name . '.mo' ) ) {
        $mo = new MO();

        if ( $mo->import_from_file( $language_dir . $mo_file_name . '.mo' ) ) {
            $translations = $mo->entries;
        }
    }

    return [
        'header'       => isset( $mo ) ? $mo->headers : '',
        'translations' => $translations,
    ];
}

/**
 * Returns Jed-formatted localization data.
 *
 * @param string $domain translation domain
 *
 * @return array
 */
function dokan_get_jed_locale_data( $domain, $language_dir = null ) {
    // get transient key
    $transient_key = sprintf( 'dokan_i18n-%s-%d-%s', $domain, filectime( $language_dir ), get_user_locale() );

    // check if data exists on cache or not
    $locale = Cache::get_transient( $transient_key );
    if ( false !== $locale ) {
        return $locale;
    }

    $plugin_translations = dokan_get_translations_for_plugin_domain( $domain, $language_dir );
    $translations        = get_translations_for_domain( $domain );

    $locale = [
        'domain'      => $domain,
        'locale_data' => [
            $domain => [
                '' => [
                    'domain' => $domain,
                    'lang'   => is_admin() ? get_user_locale() : get_locale(),
                ],
            ],
        ],
    ];

    if ( ! empty( $translations->headers['Plural-Forms'] ) ) {
        $locale['locale_data'][ $domain ]['']['plural_forms'] = $translations->headers['Plural-Forms'];
    } elseif ( ! empty( $plugin_translations['header'] ) ) {
        $locale['locale_data'][ $domain ]['']['plural_forms'] = $plugin_translations['header']['Plural-Forms'];
    }

    $entries = array_merge( $plugin_translations['translations'], $translations->entries );

    foreach ( $entries as $msgid => $entry ) {
        $locale['locale_data'][ $domain ][ $msgid ] = $entry->translations;
    }

    // store data into cache
    Cache::set_transient( $transient_key, $locale );

    return $locale;
}

/**
 * Dokan get translated days
 *
 * @since  2.8.2
 *
 * @param string|null $days
 * @maram string/null $form
 *
 * @return string|array
 */
function dokan_get_translated_days( $day = '', $form = 'long' ) {

    $all_days = [
        'sunday'    => __( 'Sunday', 'dokan-lite' ),
        'monday'    => __( 'Monday', 'dokan-lite' ),
        'tuesday'   => __( 'Tuesday', 'dokan-lite' ),
        'wednesday' => __( 'Wednesday', 'dokan-lite' ),
        'thursday'  => __( 'Thursday', 'dokan-lite' ),
        'friday'    => __( 'Friday', 'dokan-lite' ),
        'saturday'  => __( 'Saturday', 'dokan-lite' ),
    ];

    if ( 'short' === $form ) {
        $all_days = [
			'sunday'    => __( 'Sun', 'dokan-lite' ),
			'monday'    => __( 'Mon', 'dokan-lite' ),
			'tuesday'   => __( 'Tue', 'dokan-lite' ),
			'wednesday' => __( 'Wed', 'dokan-lite' ),
			'thursday'  => __( 'Thu', 'dokan-lite' ),
			'friday'    => __( 'Fri', 'dokan-lite' ),
			'saturday'  => __( 'Sat', 'dokan-lite' ),
        ];
    }

    $week_starts_on = get_option( 'start_of_week', 0 );
    $day_keys       = array_keys( $all_days );

    // Make our start day of the week using by week starts settings.
    for ( $i = 0; $i < $week_starts_on; $i++ ) {
        $shifted_key   = $day_keys[ $i ];
        $shifted_value = $all_days[ $shifted_key ];

        // Unset days and sets in the last.
        unset( $all_days[ $shifted_key ] );
        $all_days[ $shifted_key ] = $shifted_value;
    }

    // Get days array if our $days is true.
    if ( empty( $day ) ) {
        return $all_days;
    }

    if ( isset( $all_days[ $day ] ) ) {
        return $all_days[ $day ];
    }

    return apply_filters( 'dokan_get_translated_days', '', $day );
}

/**
 * Collect store times here.
 *
 * @since 3.3.7
 *
 * @param string   $day
 * @param string   $return_type eg: opening_time or closing_time
 * @param int      $index
 * @param int|null $store_id
 *
 * @return mixed|string
 */
function dokan_get_store_times( $day, $return_type, $index = null, $store_id = null ) {
    $store_id          = null === $store_id ? dokan_get_current_user_id() : $store_id;
    $store_info        = dokan_get_store_info( $store_id );
    $dokan_store_times = ! empty( $store_info['dokan_store_time'][ $day ][ $return_type ] ) ? $store_info['dokan_store_time'][ $day ][ $return_type ] : '';

    if ( empty( $dokan_store_times ) ) {
        return '';
    }

    if ( ! is_array( $dokan_store_times ) ) {
        return $dokan_store_times;
    }

    if ( is_numeric( $index ) && isset( $dokan_store_times[ $index ] ) ) {
        return $dokan_store_times[ $index ];
    }

    return $dokan_store_times[0]; // return the 1st index
}

/**
 * Dokan is store open
 *
 * @since  2.8.2
 * @since  3.2.1 replaced time related functions with dokan_current_datetime()
 *
 * @param int $user_id
 *
 * @return bool
 */
function dokan_is_store_open( $user_id ) {
    $store_user        = dokan()->vendor->get( $user_id );
    $store_info        = $store_user->get_shop_info();
    $dokan_store_times = isset( $store_info['dokan_store_time'] ) ? $store_info['dokan_store_time'] : '';

    $current_time = dokan_current_datetime();
    $today        = strtolower( $current_time->format( 'l' ) );
    $store_open   = false;

    // check if status is closed
    if ( empty( $dokan_store_times[ $today ] ) || ( isset( $dokan_store_times[ $today ]['status'] ) && 'close' === $dokan_store_times[ $today ]['status'] ) ) {
        return apply_filters( 'dokan_is_store_open', false, $today, $dokan_store_times, $user_id );
    }

    // Get store opening time.
    $opening_times = ! empty( $dokan_store_times[ $today ]['opening_time'] ) ? $dokan_store_times[ $today ]['opening_time'] : '';
    // Get single time.
    $opening_time = ! empty( $opening_times ) && is_array( $opening_times ) ? $opening_times[0] : $opening_times;
    // Convert to timestamp.
    $opening_time = ! empty( $opening_time ) ? $current_time->modify( $opening_time ) : false;

    // Get closing time.
    $closing_times = ! empty( $dokan_store_times[ $today ]['closing_time'] ) ? $dokan_store_times[ $today ]['closing_time'] : '';
    // Get single time.
    $closing_time = ! empty( $closing_times ) && is_array( $closing_times ) ? $closing_times[0] : $closing_times;
    // Convert to timestamp.
    $closing_time = ! empty( $closing_time ) ? $current_time->modify( $closing_time ) : false;

    if ( empty( $opening_time ) || empty( $closing_time ) ) {
        return apply_filters( 'dokan_is_store_open', false, $today, $dokan_store_times, $user_id );
    }

    // Check vendor picked time and current time for show store open.
    if ( $opening_time <= $current_time && $closing_time >= $current_time ) {
        $store_open = true;
    }

    return apply_filters( 'dokan_is_store_open', $store_open, $today, $dokan_store_times, $user_id );
}

/**
 * Dokan get pro buy now url
 *
 * @since 2.8.5
 *
 * @return string [url]
 */
function dokan_pro_buynow_url() {
    $link = 'https://dokan.co/wordpress/pricing/';

    if ( $aff = get_option( '_dokan_aff_ref' ) ) { // phpcs:ignore
        $link = add_query_arg( [ 'ref' => $aff ], $link );
    }

    return $link;
}

/**
 * Remove hook for anonymous class
 *
 * @param string $hook_name
 * @param string $class_name
 * @param string $method_name
 * @param int    $priority
 *
 * @return bool
 */
function dokan_remove_hook_for_anonymous_class( $hook_name = '', $class_name = '', $method_name = '', $priority = 0 ) {
    global $wp_filter;

    // Take only filters on right hook name and priority
    if ( ! isset( $wp_filter[ $hook_name ][ $priority ] ) || ! is_array( $wp_filter[ $hook_name ][ $priority ] ) ) {
        return false;
    }

    // Loop on filters registered
    foreach ( (array) $wp_filter[ $hook_name ][ $priority ] as $unique_id => $filter_array ) {
        // Test if filter is an array ! (always for class/method)
        if ( isset( $filter_array['function'] ) && is_array( $filter_array['function'] ) ) {
            // Test if object is a class, class and method is equal to param !
            if ( is_object( $filter_array['function'][0] ) && get_class( $filter_array['function'][0] ) && get_class( $filter_array['function'][0] ) === $class_name && $filter_array['function'][1] === $method_name ) {
                // Test for WordPress >= 4.7 WP_Hook class (https://make.wordpress.org/core/2016/09/08/wp_hook-next-generation-actions-and-filters/)
                if ( is_a( $wp_filter[ $hook_name ], 'WP_Hook' ) ) {
                    unset( $wp_filter[ $hook_name ]->callbacks[ $priority ][ $unique_id ] );
                } else {
                    unset( $wp_filter[ $hook_name ][ $priority ][ $unique_id ] );
                }
            }
        }
    }

    return false;
}

/**
 * Dokan get variable product earnings
 *
 * @deprecated 2.9.21
 *
 * @param int  $product_id
 * @param bool $formated
 * @param bool $deprecated
 *
 * @return float|string
 */
function dokan_get_variable_product_earning( $product_id, $formated = true, $deprecated = false ) {
    if ( $deprecated ) {
        wc_deprecated_argument( 'seller_id', '2.9.21', 'dokan_get_variable_product_earning() does not require a seller_id anymore.' );
    }

    $product = wc_get_product( $product_id );

    if ( ! $product ) {
        return null;
    }

    $variations = $product->get_children();

    if ( empty( $variations ) || ! is_array( $variations ) ) {
        return null;
    }

    $earnings = array_map(
        function ( $id ) {
            return dokan()->commission->get_earning_by_product( $id );
        }, $variations
    );

    if ( empty( $earnings ) || ! is_array( $earnings ) ) {
        return null;
    }

    if ( count( $earnings ) === 1 ) {
        return $formated ? wc_price( $earnings[0] ) : $earnings[0];
    }

    $min_earning = $formated ? wc_price( min( $earnings ) ) : min( $earnings );
    $max_earning = $formated ? wc_price( max( $earnings ) ) : max( $earnings );
    $seperator   = apply_filters( 'dokan_get_variable_product_earning_seperator', ' - ', $product_id );
    $earning     = $min_earning . $seperator . $max_earning;

    return $earning;
}

/**
 * Get page permalink of dokan pages by page id
 *
 * @since 2.9.10
 *
 * @param string $page_id
 *
 * @return string
 */
function dokan_get_permalink( $page_id ) {
    if ( ! $page_id ) {
        return false;
    }

    $pages = get_option( 'dokan_pages' );

    return isset( $pages[ $page_id ] ) ? get_permalink( $pages[ $page_id ] ) : false;
}

/**
 * Check if it's store listing page
 *
 * @since 2.9.10
 *
 * @return bool
 */
function dokan_is_store_listing() {
    $page_id = get_the_ID();
    $found   = false;

    if ( $page_id === intval( dokan_get_option( 'store_listing', 'dokan_pages' ) ) ) {
        $found = true;
    }

    if ( ! $found ) {
        $post = get_post( $page_id );

        if ( $post && false !== strpos( $post->post_content, '[dokan-stores' ) ) {
            $found = true;
        }
    }

    return apply_filters( 'dokan_is_store_listing', $found, $page_id );
}

/**
 * Dokan generate username
 *
 * @param string $name
 *
 * @return string
 */
function dokan_generate_username( $name = 'store' ) {
    static $i = 1;

    $name = implode( '', explode( ' ', $name ) );

    if ( ! username_exists( $name ) ) {
        return $name;
    }

    $new_name = sprintf( '%s-%d', $name, $i++ );

    if ( ! username_exists( $new_name ) ) {
        return $new_name;
    }

    return call_user_func( __FUNCTION__, $name );
}

/**
 * Replaces placeholders with links to policy pages.
 *
 * @since 2.9.10
 *
 * @param string $text text to find/replace within
 *
 * @return string
 */
function dokan_replace_policy_page_link_placeholders( $text ) {
    $privacy_page_id = dokan_get_option( 'privacy_page', 'dokan_privacy' );
    $privacy_link    = $privacy_page_id ? '<a href="' . esc_url( get_permalink( $privacy_page_id ) ) . '" class="dokan-privacy-policy-link" target="_blank">' . __( 'privacy policy', 'dokan-lite' ) . '</a>' : __( 'privacy policy', 'dokan-lite' );

    $find_replace = [
        '[dokan_privacy_policy]' => $privacy_link,
    ];

    return str_replace( array_keys( $find_replace ), array_values( $find_replace ), $text );
}

/**
 * Dokan privacy policy text
 *
 * @since 2.9.10
 * @since DOKAN_LITE_VERSION Add `$return` param to return the text on demand instead of printing
 *
 * @param bool $return
 *
 * @return string
 */
function dokan_privacy_policy_text( $return = false ) {
    $is_enabled   = 'on' === dokan_get_option( 'enable_privacy', 'dokan_privacy' );
    $privacy_page = dokan_get_option( 'privacy_page', 'dokan_privacy' );
    $privacy_text = dokan_get_option( 'privacy_policy', 'dokan_privacy', __( 'Your personal data will be used to support your experience throughout this website, to manage access to your account, and for other purposes described in our [dokan_privacy_policy]', 'dokan-lite' ) );

    if ( ! $is_enabled || ! $privacy_page ) {
        return '';
    }

    $text = wpautop( dokan_replace_policy_page_link_placeholders( $privacy_text ), true );

    if ( $return ) {
        return wp_kses_post( $text );
    }

    echo wp_kses_post( $text );
}

/**
 * Dokan commission types
 *
 * @since 2.9.21
 *
 * @return array
 */
function dokan_commission_types() {
    return apply_filters(
        'dokan_commission_types', [
            'fixed'          => __( 'Fixed', 'dokan-lite' ),
            'category_based' => __( 'Category Based', 'dokan-lite' ),
        ]
    );
}

/**
 * Dokan Login Form
 *
 * @since 2.9.11
 *
 * @param array $args
 * @param bool  $echo
 *
 * @return void|string
 */
function dokan_login_form( $args = [], $echo = false ) {
    $login_url = apply_filters( 'dokan_redirect_login', dokan_get_page_url( 'myaccount', 'woocommerce' ) );

    $defaults = [
        'id'           => 'dokan-login-form',
        'nonce_action' => 'dokan-login-form-action',
        'nonce_name'   => 'dokan-login-form-nonce',
        'login_url'    => $login_url,
    ];

    $args = wp_parse_args( $args, $defaults );

    if ( $echo ) {
        dokan_get_template_part( 'login-form/login-form', false, $args );
    } else {
        ob_start();
        dokan_get_template_part( 'login-form/login-form', false, $args );

        return ob_get_clean();
    }
}

/**
 * Validate a boolean variable
 *
 * @since 2.9.12
 *
 * @param mixed $var
 *
 * @return bool
 */
function dokan_validate_boolean( $var ) {
    return filter_var( $var, FILTER_VALIDATE_BOOLEAN );
}

/**
 * Backward compatibile settings option map
 *
 * @since 2.9.21
 *
 * @param string $option
 * @param string $section
 *
 * @return array
 */
function dokan_admin_settings_rearrange_map( $option, $section ) {
    $id = $option . '_' . $section;

    $map = apply_filters(
        'dokan_admin_settings_rearrange_map', [
            'shipping_fee_recipient_dokan_general'     => [ 'shipping_fee_recipient', 'dokan_selling' ],
            'tax_fee_recipient_dokan_general'          => [ 'tax_fee_recipient', 'dokan_selling' ],
            'store_open_close_dokan_general'           => [ 'store_open_close', 'dokan_appearance' ],
            'store_map_dokan_general'                  => [ 'store_map', 'dokan_appearance' ],
            'gmap_api_key_dokan_general'               => [ 'gmap_api_key', 'dokan_appearance' ],
            'contact_seller_dokan_general'             => [ 'contact_seller', 'dokan_appearance' ],
            'enable_theme_store_sidebar_dokan_general' => [ 'enable_theme_store_sidebar', 'dokan_appearance' ],
            'setup_wizard_logo_url_dokan_appearance'   => [ 'setup_wizard_logo_url', 'dokan_general' ],
            'disable_welcome_wizard_dokan_selling'     => [ 'disable_welcome_wizard', 'dokan_general' ],
        ]
    );

    if ( isset( $map[ $id ] ) ) {
        return $map[ $id ];
    }

    return [ $option, $section ];
}

/**
 * Dokan get terms and condition page url
 *
 * @since 2.9.16
 *
 * @return string | null on failure
 */
function dokan_get_terms_condition_url() {
    $page_id = dokan_get_option( 'reg_tc_page', 'dokan_pages' );

    if ( ! $page_id ) {
        return null;
    }

    return apply_filters( 'dokan_get_terms_condition_url', get_permalink( $page_id ), $page_id );
}

if ( ! function_exists( 'dokan_get_seller_status_count' ) ) {
    /**
     * Get Seller status counts, used in admin area
     *
     * @since 2.9.23
     *
     * @return array
     */
    function dokan_get_seller_status_count() {
        $active_users = new WP_User_Query(
            [
                'role__in'   => [ 'seller', 'administrator' ],
                'meta_key'   => 'dokan_enable_selling', // phpcs:ignore
                'meta_value' => 'yes', // phpcs:ignore
                'fields'     => 'ID',
            ]
        );

        $all_users      = new WP_User_Query(
            [
                'role__in' => [ 'seller', 'administrator' ],
                'fields'   => 'ID',
            ]
        );
        $active_count   = $active_users->get_total();
        $inactive_count = $all_users->get_total() - $active_count;

        return apply_filters(
            'dokan_get_seller_status_count', [
                'total'    => $active_count + $inactive_count,
                'active'   => $active_count,
                'inactive' => $inactive_count,
            ]
        );
    }
}

/**
 * Install a plugin from wp.org
 *
 * Example:
 * To download WooCommerce `dokan_install_wp_org_plugin( 'woocommerce' )`
 * To download plugin like dokan-lite that has different slug and main plugin file,
 * `dokan_install_wp_org_plugin( 'dokan-lite', 'dokan.php' )`
 *
 * @since 2.9.27
 *
 * @param string $plugin_slug
 * @param string $main_file
 *
 * @return bool|\WP_Error
 */
function dokan_install_wp_org_plugin( $plugin_slug, $main_file = null ) {
    $plugin = $plugin_slug . '/' . ( $main_file ? $main_file : $plugin_slug . '.php' );

    if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin ) ) {
        include_once ABSPATH . 'wp-admin/includes/file.php';
        include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
        include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';

        $api = plugins_api(
            'plugin_information', [
                'slug'   => $plugin_slug,
                'fields' => [
                    'sections' => false,
                ],
            ]
        );

        if ( is_wp_error( $api ) ) {
            return new WP_Error(
                'dokan_install_wp_org_plugin_error_api',
                // translators: 1) plugin slug
                sprintf( __( 'Unable to fetch plugin information from wordpress.org for %s.', 'dokan-lite' ), $plugin_slug )
            );
        }

        $upgrader  = new Plugin_Upgrader( new WP_Ajax_Upgrader_Skin() );
        $installed = $upgrader->install( $api->download_link );

        if ( is_wp_error( $installed ) ) {
            return $installed;
        } elseif ( ! $installed ) {
            return new WP_Error(
                'dokan_install_wp_org_plugin_error',
                // translators: 1) plugin slug
                sprintf( __( 'Unable to install %s from wordpress.org', 'dokan-lite' ), $plugin_slug )
            );
        }
    }

    $activate_plugin = activate_plugin( $plugin );

    if ( is_wp_error( $activate_plugin ) ) {
        return $activate_plugin;
    }

    return true;
}

/**
 * Redirect to Dokan admin setup wizard page
 *
 * @since 2.9.27
 *
 * @return void
 */
function dokan_redirect_to_admin_setup_wizard() {
    // Delete the redirect transient
    delete_transient( '_dokan_setup_page_redirect' );

    wp_safe_redirect( add_query_arg( [ 'page' => 'dokan-setup' ], admin_url( 'index.php' ) ) );
    exit;
}

/**
 * Dokan generate star ratings
 *
 * @since  3.0.0
 *
 * @param int $rating Number of rating point
 * @param int $starts Total number of stars
 *
 * @return string
 */
function dokan_generate_ratings( $rating, $stars ) {
    $result = '';
    $rating = wc_format_decimal( floatval( $rating ), 2 );

    for ( $i = 1; $i <= $stars; $i++ ) {
        if ( $rating >= $i ) {
            $result .= "<i class='dashicons dashicons-star-filled'></i>";
        } elseif ( $rating > ( $i - 1 ) && $rating < $i ) {
            $result .= "<i class='dashicons dashicons-star-half'></i>";
        } else {
            $result .= "<i class='dashicons dashicons-star-empty'></i>";
        }
    }

    return apply_filters( 'dokan_generate_ratings', $result );
}

/**
 * Check if current PHP version met the minimum requried PHP version for WooCommerce
 *
 * @since 3.0.0
 *
 * @param string $required_version
 *
 * @return bool
 */
function dokan_met_minimum_php_version_for_wc( $required_version = '7.0' ) {
    return apply_filters( 'dokan_met_minimum_php_version_for_wc', version_compare( PHP_VERSION, $required_version, '>=' ), $required_version );
}

/**
 * Checks if Dokan settings has map api key
 *
 * @since 3.0.2
 *
 * @return bool
 */
function dokan_has_map_api_key() {
    $dokan_appearance = get_option( 'dokan_appearance', [] );

    if ( ! empty( $dokan_appearance['map_api_source'] ) && 'google_maps' === $dokan_appearance['map_api_source'] && ! empty( $dokan_appearance['gmap_api_key'] ) ) {
        return true;
    } elseif ( ! empty( $dokan_appearance['map_api_source'] ) && 'mapbox' === $dokan_appearance['map_api_source'] && ! empty( $dokan_appearance['mapbox_access_token'] ) ) {
        return true;
    }

    return false;
}

/**
 * Dokan clear product caches.
 * We'll be calling `WC_Product_Data_Store_CPT::clear_caches()` to clear product caches.
 *
 * @since 3.0.3
 *
 * @param int|\WC_Product $product
 *
 * @return void
 */
function dokan_clear_product_caches( $product ) {
    if ( ! $product instanceof \WC_Product ) {
        $product = wc_get_product( $product );
    }

    $store       = \WC_Data_Store::load( 'product-' . $product->get_type() );
    $class       = $store->get_current_class_name();
    $class       = is_object( $class ) ? $class : new $class();
    $reflection  = new \ReflectionClass( $class );
    $method_name = 'clear_caches';

    if ( ! $reflection->hasMethod( $method_name ) ) {
        return;
    }

    $method = $reflection->getMethod( $method_name );
    $method->setAccessible( true );
    $method->invokeArgs( $class, [ &$product ] );
}

/**
 * Check which vendor info should be hidden
 *
 * @since 3.0.4
 *
 * @param string $option
 *
 * @return bool|array if no param is passed
 */
function dokan_is_vendor_info_hidden( $option = null ) {
    $options = dokan_get_option( 'hide_vendor_info', 'dokan_appearance' );

    if ( is_null( $option ) ) {
        return $options;
    }

    return ! empty( $options[ $option ] );
}

/**
 * Function current_datetime() compatibility for wp version < 5.3
 *
 * @since 3.1.1
 *
 * @return DateTimeImmutable
 */
function dokan_current_datetime() {
    if ( function_exists( 'current_datetime' ) ) {
        return current_datetime();
    }

    return new DateTimeImmutable( 'now', dokan_wp_timezone() );
}

/**
 * Function wp_timezone() compatibility for wp version < 5.3
 *
 * @since 3.1.1
 *
 * @return DateTimeZone
 */
function dokan_wp_timezone() {
    if ( function_exists( 'wp_timezone' ) ) {
        return wp_timezone();
    }

    return new DateTimeZone( dokan_wp_timezone_string() );
}

/**
 * Function wp_timezone_string() compatibility for wp version < 5.3
 *
 * @since 3.1.1
 *
 * @return string
 */
function dokan_wp_timezone_string() {
    if ( function_exists( 'wp_timezone_string' ) ) {
        return wp_timezone_string();
    }

    $timezone_string = get_option( 'timezone_string' );

    if ( $timezone_string ) {
        return $timezone_string;
    }

    $offset  = (float) get_option( 'gmt_offset' );
    $hours   = (int) $offset;
    $minutes = ( $offset - $hours );

    $sign      = ( $offset < 0 ) ? '-' : '+';
    $abs_hour  = abs( $hours );
    $abs_mins  = abs( $minutes * 60 );
    $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );

    return $tz_offset;
}

/**
 * Get a formatted date, time from WordPress format
 *
 * @since 3.2.7
 *
 * @param string|bool                  $format date format string or false for default WordPress date
 * @param string|int|DateTimeImmutable $date   the date string or timestamp or DateTimeImmutable object
 *
 * @return string|false The date, translated if locale specifies it. False on invalid timestamp input.
 */
function dokan_format_datetime( $date = '', $format = false ) {
    // if no format is specified, get default WordPress date format
    if ( ! $format ) {
        $format = wc_date_format() . ' ' . wc_time_format();
    }

    // if date is empty, get current datetime timestamp
    if ( empty( $date ) ) {
        $timestamp = dokan_current_datetime()->getTimestamp();
        // if date is not timestamp, convert it to timestamp
    } elseif ( $date instanceof DateTimeImmutable ) {
        $timestamp = $date->getTimestamp();
        // if the date param is string, convert it to timestamp
    } elseif ( is_numeric( $date ) ) {
        $timestamp = $date;
    } elseif ( is_string( $date ) && strtotime( $date ) ) {
        $timestamp = dokan_current_datetime()->modify( $date )->getTimestamp();
        // if date is already timestamp, just use it
    } else {
        // we couldn't recognize the $date argument
        return false;
    }

    if ( function_exists( 'wp_date' ) ) {
        return wp_date( $format, $timestamp );
    }

    return date_i18n( $format, $timestamp );
}

/**
 * Get a formatted date from WordPress format
 *
 * @since 3.1.1
 *
 * @param string|int|DateTimeImmutable $date   the date string or timestamp or DateTimeImmutable object
 * @param string|bool                  $format date format string or false for default WordPress date
 *
 * @return string|false The date, translated if locale specifies it. False on invalid timestamp input.
 */
function dokan_format_date( $date = '', $format = false ) {
    // if no format is specified, get default WordPress date format
    if ( ! $format ) {
        $format = wc_date_format();
    }

    return dokan_format_datetime( $date, $format );
}

/**
 * Get a formatted time from WordPress format
 *
 * @since 3.5.1
 *
 * @param string|int|DateTimeImmutable $date   the date string or timestamp or DateTimeImmutable object
 * @param string|bool                  $format date format string or false for default WordPress date
 *
 * @return string|false The date, translated if locale specifies it. False on invalid timestamp input.
 */
function dokan_format_time( $date = '', $format = false ) {
    // if no format is specified, get default WordPress date format
    if ( ! $format ) {
        $format = wc_time_format();
    }

    return dokan_format_datetime( $date, $format );
}

/**
 * Create an expected date time format from a given format.
 *
 * @since 3.7.1
 *
 * @param string $format      Date string format
 * @param string $date_string Date time string
 *
 * @return DateTimeImmutable|false
 */
function dokan_create_date_from_format( $format, $date_string ) {
    return \DateTimeImmutable::createFromFormat(
        $format,
        $date_string,
        new \DateTimeZone( dokan_wp_timezone_string() )
    );
}

/**
 * Convert times in expected format.
 *
 * @param array|string $times_data    Times data
 * @param string       $input_format  Times current format
 * @param string       $output_format Times converted format
 *
 * @return string|array
 */
function dokan_convert_date_format( $times_data, $input_format = 'g:i a', $output_format = 'g:i a' ) {
    if ( empty( $times_data ) ) {
        return $times_data;
    }

    $times = [];
    foreach ( (array) $times_data as $time ) {
        $datetime = dokan_create_date_from_format( $input_format, $time );
        $times[]  = $datetime ? $datetime->format( $output_format ) : '';
    }

    return is_string( $times_data ) ? $times[0] : $times;
}

/**
 * This method will convert datetime string into timestamp
 *
 * @since 3.2.15
 *
 * @param string $date_string
 * @param bool   $gmt_date
 *
 * @return bool|int date timestamp on success, false otherwise
 */
function dokan_get_timestamp( $date_string, $gmt_date = false ) {
    // get current time
    $now = dokan_current_datetime();
    // convert to gmt time
    if ( $gmt_date ) {
        $now = $now->setTimezone( new DateTimeZone( 'UTC' ) );
    }
    // modify current date
    $now = $now->modify( $date_string );

    return $now ? $now->getTimestamp() : false;
}

/**
 * Get inverval between two dates, useful for chart functions
 *
 * @since 3.7.0
 *
 * @param string|int $start_date
 * @param string|int $end_date
 * @param string     $group_by
 *
 * @return false|int
 */
function dokan_get_interval_between_dates( $start_date, $end_date, $group_by = 'day' ) {
    $now        = dokan_current_datetime();
    $start_date = is_numeric( $start_date ) ? $now->setTimestamp( $start_date ) : $now->modify( $start_date );
    $end_date   = is_numeric( $end_date ) ? $now->setTimestamp( $end_date ) : $now->modify( $end_date );

    if ( ! $start_date || ! $end_date ) {
        // invalid start or end date
        return 0;
    }

    $date_interval = $start_date->diff( $end_date );

    return $group_by === 'day' ? $date_interval->days : $date_interval->m;
}

if ( ! function_exists( 'dokan_date_time_format' ) ) {

    /**
     * Format date time string to WC format
     *
     * @since 2.6.8
     * @since 3.7.0 This method was moved from wc-functions.php
     *
     * @param string  $time
     * @param boolean $date_only
     *
     * @deprecated 3.8.0
     *
     * @return string
     */
    function dokan_date_time_format( $time, $date_only = false ) {
        wc_deprecated_function( 'dokan_date_time_format', '3.8.0', 'dokan_format_datetime()' );
        $format = apply_filters( 'dokan_date_time_format', wc_date_format() . ' ' . wc_time_format() );

        if ( $date_only ) {
            return date_i18n( wc_date_format(), strtotime( $time ) );
        }

        return date_i18n( $format, strtotime( $time ) );
    }
}

/**
 * Get threshold day for a user
 *
 * @since 3.2.2
 *
 * @param int $user_id
 *
 * @return int threshold day
 */
function dokan_get_withdraw_threshold( $user_id ) {
    if ( get_user_meta( $user_id, 'withdraw_date_limit', true ) !== '' ) {
        $threshold_day = get_user_meta( $user_id, 'withdraw_date_limit', true );
    } else {
        $threshold_day = dokan_get_option( 'withdraw_date_limit', 'dokan_withdraw', 0 );
    }

    return ( $threshold_day ) ? absint( $threshold_day ) : 0;
}

/**
 * Mask or hide part of email address.
 *
 * @since 3.3.1
 *
 * @param string $email Email address
 *
 * @return string
 */
function dokan_mask_email_address( $email ) {
    if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
        return $email;
    }

    [ $first, $last ] = explode( '@', $email );
    $first       = str_replace( substr( $first, '1' ), str_repeat( '*', strlen( $first ) - 1 ), $first );
    $last        = explode( '.', $last );
    $last_domain = str_replace( substr( $last['0'], '1' ), str_repeat( '*', strlen( $last['0'] ) - 1 ), $last['0'] );

    return "{$first}@{$last_domain}.{$last['1']}";
}

/**
 * Mask or hide part of string.
 *
 * @since 3.7.22
 *
 * @param string  $text text
 * @param integer $position
 *
 * @return string
 */
function dokan_mask_string( $text, $position = 1, $show_max_letters = 4 ) {
    $first_letters = substr( $text, 0, $position );
    $remaining_letters = substr( $text, 2 );

    $masked_letters = str_repeat( '*', min( $show_max_letters, strlen( $remaining_letters ) ) );

    return $first_letters . $masked_letters;
}

/**
 * Add item in specific position of an array
 *
 * @since 2.9.21
 *
 * @param array      $array
 * @param int|string $position <index position or name of the key after which you want to add the new array>
 * @param array      $new_array
 *
 * @return array
 */
function dokan_array_after( $array, $position, $new_array ) {
    if ( is_int( $position ) ) {
        return array_merge(
            array_slice( $array, 0, $position ),
            $new_array,
            array_slice( $array, $position )
        );
    }

    $pos = array_search( $position, array_keys( $array ), true );

    return array_merge(
        array_slice( $array, 0, $pos + 1 ),
        $new_array,
        array_slice( $array, $pos )
    );
}

/**
 * Insert a value or key/value pair (assoc array) after a specific key in an array.  If key doesn't exist, value is appended
 * to the end of the array.
 *
 * @since 3.2.16
 *
 * @param array  $old_array
 * @param array  $new_array
 * @param string $insert_after_key
 *
 * @return array
 */
function dokan_array_insert_after( array $old_array, array $new_array, $insert_after_key = '' ) {
    $keys  = array_keys( $old_array );
    $index = ! empty( $insert_after_key ) ? array_search( $insert_after_key, $keys, true ) : false;
    $pos   = false === $index ? count( $old_array ) : $index + 1;

    return array_slice( $old_array, 0, $pos, true ) + $new_array + array_slice( $old_array, $pos, count( $old_array ) - 1, true );
}

/**
 * Check a order have apply admin coupon
 *
 * @since 3.2.16
 *
 * @param WC_Order $order
 * @param int      $vendor_id
 * @param int      $product_id
 *
 * @return bool
 */
function dokan_is_admin_coupon_applied( $order, $vendor_id, $product_id = 0 ) {
    if (
        function_exists( 'dokan_is_admin_coupon_used_for_vendors' ) &&
        dokan_is_admin_coupon_used_for_vendors( $order, $vendor_id, $product_id ) ) {
        return true;
    }

    return false;
}

/**
 * Get vendor store banner width
 *
 * Added new filter hook for vendor store
 * banner width size @hook dokan_store_banner_default_width
 *
 * @since 3.2.15
 *
 * @return int $width Banner width
 */
function dokan_get_vendor_store_banner_width() {
    $width = absint( apply_filters( 'dokan_store_banner_default_width', dokan_get_option( 'store_banner_width', 'dokan_appearance', 625 ) ) );

    return ( $width !== 0 ) ? $width : 625;
}

/**
 * Get vendor store banner height
 *
 * Added new filter hook for vendor
 * store banner height size @hook dokan_store_banner_default_height
 *
 * @since 3.2.15
 *
 * @return int $height Banner height
 */
function dokan_get_vendor_store_banner_height() {
    $height = absint( apply_filters( 'dokan_store_banner_default_height', dokan_get_option( 'store_banner_height', 'dokan_appearance', 300 ) ) );

    return ( $height !== 0 ) ? $height : 300;
}

/**
 * Get google recaptcha site key and secret key
 *
 * @since 3.3.3
 *
 * @deprecated 4.3.0
 *
 * @param bool $boolean
 *
 * @return array|bool
 */
function dokan_get_recaptcha_site_and_secret_keys( $boolean = false ) {
    $recaptcha_keys = [
        'site_key'   => dokan_get_option( 'recaptcha_site_key', 'dokan_appearance' ),
        'secret_key' => dokan_get_option( 'recaptcha_secret_key', 'dokan_appearance' ),
    ];

    $is_disabled = 'off' === dokan_get_option( 'recaptcha_enable_status', 'dokan_appearance', 'on' );

    if ( $boolean ) {
        if ( empty( $recaptcha_keys['site_key'] ) || empty( $recaptcha_keys['secret_key'] ) || $is_disabled ) {
            return false;
        }

        return true;
    }

    return $recaptcha_keys;
}

/**
 * Handle google reCaptcha validation request.
 *
 * @since 3.3.6
 * @deprecated 4.3.0
 *
 * @param string $action
 * @param string $token
 * @param string $secretkey
 *
 * @return boolean
 */
function dokan_handle_recaptcha_validation( $action, $token, $secretkey ) {
    // Check if action, token and secret key exist.
    if ( empty( $action ) || empty( $token ) || empty( $secretkey ) ) {
        return false;
    }

    // Response data.
    $siteverify    = 'https://www.google.com/recaptcha/api/siteverify';
    $response      = wp_remote_get( $siteverify . '?secret=' . $secretkey . '&response=' . $token );
    $response_body = wp_remote_retrieve_body( $response );
    $response_data = json_decode( $response_body, true );

    // Check if the response data is not empty.
    if ( empty( $response_data['success'] ) ) {
        return false;
    }

    // Validate reCaptcha action.
    if ( empty( $response_data['action'] ) || $action !== $response_data['action'] ) {
        return false;
    }

    // Validate reCaptcha score.
    $min_eligible_score = apply_filters( 'dokan_recaptcha_minimum_eligible_score', 0.5, $action );
    if ( empty( $response_data['score'] ) || $response_data['score'] < $min_eligible_score ) {
        return false;
    }

    // Return success status after passing checks.
    return $response_data['success'];
}

/**
 * Get additional products sections.
 *
 * @since 3.3.6
 *
 * @return array
 */
function dokan_get_additional_product_sections() {
    return dokan()->product_sections->get_available_product_sections();
}

/**
 * Converts a 'on' or 'off' to boolean
 *
 * @since 3.3.6
 *
 * @param string $value
 *
 * @return bool
 */
function dokan_string_to_bool( $value ) {
    return is_bool( $value ) ? $value : ( in_array( strtolower( $value ?? '' ), [ 'yes', 1, '1', 'true', 'on' ], true ) );
}

/**
 * Converts a boolean value to a 'on' or 'off'.
 *
 * @since 3.3.7
 *
 * @param bool $bool
 *
 * @return string
 */
function dokan_bool_to_on_off( $bool ) {
    if ( ! is_bool( $bool ) ) {
        $bool = dokan_string_to_bool( $bool );
    }

    return true === $bool ? 'on' : 'off';
}

/**
 * Check is 12-hour format in current setup.
 *
 * @since 3.6.0
 *
 * @return bool
 */
function is_tweleve_hour_format() {
    // Check if current setup format is 12 hour format.
    return preg_match( '/(am|pm)$/i', dokan_current_datetime()->format( wc_time_format() ) );
}

/**
 * Sanitize phone number.
 * Allows only numbers and "+" (plus sign) "." (full stop) "(" ")" "-".
 *
 * @since 3.7.0
 *
 * @param string $phone Phone number.
 *
 * @return string
 */
function dokan_sanitize_phone_number( $phone ) {
	return preg_replace( '/[^0-9()._+-]/', '', $phone );
}

/**
 * Dokan override author ID from admin
 *
 * @since  2.6.2
 * @since 3.7.18 moved this method from includes/Admin/functions.php file
 *
 * @param  WC_Product $product
 * @param  integer $seller_id
 *
 * @return void
 */
function dokan_override_product_author( $product, $seller_id ) {
    wp_update_post(
        [
            'ID'          => $product->get_id(),
            'post_author' => $seller_id,
        ]
    );

    dokan_override_author_for_product_variations( $product, $seller_id );

    do_action( 'dokan_after_override_product_author', $product, $seller_id );
}

/**
 * Overrides author for products with variations.
 *
 * @since 3.7.4
 * @since 3.7.18 moved this method from includes/Admin/functions.php file
 *
 * @param WC_Product $product
 * @param int        $seller_id
 *
 * @return void
 */
function dokan_override_author_for_product_variations( $product, $seller_id ) {
    if ( 'variable' === $product->get_type() || 'variable-subscription' === $product->get_type() ) {
        $variations = $product->get_children();

        foreach ( $variations as $variation_id ) {
            wp_update_post(
                [
                    'ID'          => $variation_id,
                    'post_author' => $seller_id,
                ]
            );
        }
    }
}

/**
 * Handle user update from customer to seller.
 *
 * @since 3.7.21
 *
 * @param object $user User Object
 * @param array  $data Data to Update
 *
 * @return void
 */
if ( ! function_exists( 'dokan_user_update_to_seller' ) ) {

    function dokan_user_update_to_seller( $user, $data ) {
        if ( ! is_a( $user, WP_User::class ) || dokan_is_user_seller( $user->ID ) ) {
            return;
        }

        $user_id       = $user->ID;
        $current_roles = (array) $user->roles;

        // Remove role
        $user->remove_role( 'customer' );
        if ( is_array( $current_roles ) ) {
            foreach ( $current_roles as $current_role ) {
                $user->remove_role( $current_role );
            }
        }

        // Add role
        $user->add_role( 'seller' );

        $user_id = wp_update_user(
            [
                'ID'            => $user_id,
                'user_nicename' => $data['shopurl'],
            ]
        );
        update_user_meta( $user_id, 'first_name', $data['fname'] );
        update_user_meta( $user_id, 'last_name', $data['lname'] );

        /**
         * @var $vendor \WeDevs\Dokan\Vendor\Vendor
         */
        $vendor = dokan()->vendor->get( $user_id );
        $vendor->set_store_name( $data['shopname'] );
        $vendor->set_phone( $data['phone'] );
        $vendor->set_address( $data['address'] );
        $vendor->save();

        if ( 'automatically' === dokan_get_container()->get( \WeDevs\Dokan\Utilities\AdminSettings::class )->get_new_seller_enable_selling_status() ) {
            $vendor->make_active();
        } else {
            $vendor->make_inactive();
        }

        update_user_meta( $user_id, 'dokan_publishing', 'no' );

        do_action( 'dokan_new_seller_created', $user_id, $vendor->get_shop_info() );
    }
}

/**
 * Get new product creation URL.
 *
 * @since 3.9.7
 *
 * @return false|string
 */
function dokan_get_new_product_url() {
    $one_step_product_create = 'on' === dokan_get_option( 'one_step_product_create', 'dokan_selling', 'on' );

    return $one_step_product_create ? dokan_edit_product_url( 0, true ) : add_query_arg(
        [
            '_dokan_add_product_nonce' => wp_create_nonce( 'dokan_add_product_nonce' ),
        ],
        dokan_get_navigation_url( 'new-product' )
    );
}
