<?php
/**
 * Main Plugin Class
 *
 * @since   PBOOKING_SINCE
 * @package Nemtly_Booking
 */

namespace NemtlyBooking\Core;

use NemtlyBooking\API\Events_Controller;
use NemtlyBooking\Core\Module_Manager;
use NemtlyBooking\Blocks\Block_Registry;
use NemtlyBooking\Integrations\Elementor\Elementor_Integration;

/**
 * Plugin class
 *
 * Main plugin bootstrap class that initializes all components
 *
 * @since PBOOKING_SINCE
 */
class Plugin {


    /**
     * Plugin instance
     *
     * @var Plugin
     */
    private static $instance = null;

    /**
     * Dependency injection container
     *
     * @var Container
     */
    private $container;

    /**
     * Service container
     *
     * @var Service_Container
     */
    private $service_container;

    /**
     * Module manager
     *
     * @var Module_Manager
     */
    private $module_manager;

    /**
     * Events REST controller
     *
     * @var Events_Controller
     */
    private $events_controller;

    /**
     * Admin class holder
     *
     * @var Admin
     */
    private $admin;

    /**
     * Block Registry
     *
     * @var Block_Registry
     */
    private $block_registry;

    /**
     * Get plugin instance
     *
     * @since PBOOKING_SINCE
     *
     * @return Plugin
     */
    public static function get_instance()
    {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * Constructor
     *
     * @since PBOOKING_SINCE
     */
    private function __construct()
    {
        $this->define_constants();
        $this->init_container();
        $this->init_hooks();

        // Initialize Block Registry
        $this->block_registry = new Block_Registry( $this->container );
        add_action( 'init', [ $this->block_registry, 'init' ] );

        // Block themes render events via the FSE templates registered here.
        $template_manager = new Block_Template_Manager();
        $template_manager->init();

        // Classic themes render the same events views through PHP templates.
        $classic_template_loader = new Classic_Template_Loader();
        $classic_template_loader->init();

        // Initialize Pattern Manager
        $pattern_manager = new Pattern_Manager();
        $pattern_manager->init();

        // Register Elementor widgets (self-guarding — hooks only fire when Elementor is active).
        $elementor_integration = new Elementor_Integration();
        $elementor_integration->init();
    }

    /**
     * Initialize dependency injection container
     *
     * @since PBOOKING_SINCE
     */
    private function init_container()
    {
        $this->container         = new Container();
        $this->service_container = new Service_Container( $this->container );
        $this->module_manager    = new Module_Manager( $this->container );
        $this->service_container->register_services();
    }

    /**
     * Define plugin constants
     *
     * @since PBOOKING_SINCE
     */
    private function define_constants()
    {
        $this->define( 'NEMTLY_BOOKING_VERSION', '2.0.1' );
        $this->define( 'NEMTLY_BOOKING_DIR', plugin_dir_path( NEMTLY_BOOKING_FILE ) );
        $this->define( 'NEMTLY_BOOKING_PATH', plugin_dir_path( NEMTLY_BOOKING_FILE ) );
        $this->define( 'NEMTLY_BOOKING_URL', plugin_dir_url( NEMTLY_BOOKING_FILE ) );
        $this->define( 'NEMTLY_BOOKING_ASSETS', NEMTLY_BOOKING_URL . 'assets' );
        $this->define( 'NEMTLY_BOOKING_INCLUDES', NEMTLY_BOOKING_URL . 'includes' );
        $this->define( 'NEMTLY_BOOKING_TELEMETRY_TOKEN', '3c6f5df3-7797-4394-89b5-27d54de2ba77' );
    }

    /**
     * Define constant if not already set.
     *
     * @param string $name  The name of the constant to define.
     * @param mixed  $value The value of the constant.
     */
    private function define( $name, $value )
    {
        if ( ! defined( $name ) ) {
            define( $name, $value );
        }
    }

    /**
     * Initialize hooks
     *
     * @since PBOOKING_SINCE
     */
    private function init_hooks()
    {
        register_activation_hook( NEMTLY_BOOKING_FILE, [ $this, 'activate' ] );
        register_deactivation_hook( NEMTLY_BOOKING_FILE, [ $this, 'deactivate' ] );
        add_action( 'init', [ $this, 'init' ] );

        // Boot telemetry on init so its translated strings load at the correct time
        // (weekly opt-in usage report + deactivation survey).
        add_action( 'init', [ Telemetry_Manager::class, 'init' ] );

        // Initialize REST API
        add_action( 'rest_api_init', [ $this, 'init_rest_api' ] );

        // Stripe webhook endpoint (action-based URL).
        add_action( 'init', [ $this, 'maybe_handle_stripe_webhook' ], 20 );

        // Register post types and taxonomies
        add_action( 'init', [ $this, 'register_post_types' ] );
        add_action( 'init', [ $this, 'register_taxonomies' ] );

        // Add Open Graph meta tags
        add_action( 'wp_head', [ $this, 'add_event_meta_tags' ] );

        // Support sorting by meta_value in REST API for events
        add_filter( 'rest_nemtly_event_collection_params', [ $this, 'add_rest_orderby_params' ] );
        add_filter( 'rest_nemtly_event_query', [ $this, 'handle_rest_orderby_params' ], 10, 2 );

        // Initialize admin functionality
        if ( is_admin() ) {
            $this->admin = new Admin();
        }
    }

    /**
     * Initialize plugin
     *
     * @since PBOOKING_SINCE
     */
    public function init()
    {
        // Register custom post types
        $this->register_post_types();

        // Initialize services
        $this->service_container->init_services();

        // Register modules
        $this->register_modules();

        // Initialize modules
        $this->module_manager->initialize_modules();

        // Connect admin with booking module after services are initialized
        if ( is_admin() && $this->admin ) {
            $booking_module = $this->container->get( 'booking_module' );
            $this->admin->set_booking_module( $booking_module );
        }
    }

    /**
     * Handle Stripe webhook when request is to ?action=nemtly_stripe_payment_response
     *
     * @since PBOOKING_SINCE
     */
    public function maybe_handle_stripe_webhook() {
        if ( ! isset( $_GET['action'] ) || 'nemtly_stripe_payment_response' !== sanitize_text_field( wp_unslash( $_GET['action'] ) ) ) {
            return;
        }
        if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
            return;
        }

        $payload = file_get_contents( 'php://input' );

        if ( false === $payload || '' === $payload ) {
            http_response_code( 400 );
            exit;
        }

        $sig_header = '';

        if ( isset( $_SERVER['HTTP_STRIPE_SIGNATURE'] ) && is_string( $_SERVER['HTTP_STRIPE_SIGNATURE'] ) ) {
            $sig_header = sanitize_text_field( wp_unslash( $_SERVER['HTTP_STRIPE_SIGNATURE'] ) );
        }

        if ( empty( $sig_header ) ) {
            http_response_code( 400 );
            exit;
        }

        $payment_service = $this->container->get( 'payment_service' );
        $payment_service->handle_webhook( $payload, $sig_header );
        exit;
    }

    /**
     * Register modules
     *
     * @since PBOOKING_SINCE
     */
    private function register_modules()
    {
        // Register core modules
        $event_module   = $this->container->get( 'event_module' );
        $booking_module = $this->container->get( 'booking_module' );

        $this->module_manager->register_module( $event_module );
        $this->module_manager->register_module( $booking_module );

        // Allow third-party modules to be registered
        $additional_modules = apply_filters( 'nemtly_booking_modules', [] );
        foreach ( $additional_modules as $module ) {
            $this->module_manager->register_module( $module );
        }
    }

    /**
     * Initialize REST API
     *
     * @since PBOOKING_SINCE
     */
    public function init_rest_api()
    {
        // Initialize REST API controllers via service container
        $this->service_container->init_api_controllers();
    }

    /**
     * Plugin activation
     *
     * @since PBOOKING_SINCE
     */
    public function activate()
    {
        // Create database tables if needed
        $this->create_tables();

        // Schedule hourly reminder event
        if ( ! wp_next_scheduled( 'nemtly_booking_hourly_reminder' ) ) {
            wp_schedule_event( time(), 'hourly', 'nemtly_booking_hourly_reminder' );
        }

        // Register CPT and taxonomies before flushing so their rewrite rules are written to the rules table
        $this->register_post_types();
        $this->register_taxonomies();
        flush_rewrite_rules();

        // Ensure the customer dashboard page exists (idempotent — reused by title).
        ( new \NemtlyBooking\Services\Setup_Service() )->create_page_for_role( 'dashboard' );

        // Flag a one-shot redirect to the setup wizard. Skipped on multisite
        // network activation and bulk activation so we don't hijack those flows.
        if ( ! is_network_admin() && ! isset( $_GET['activate-multi'] ) ) {
            set_transient( 'nemtly_booking_activation_redirect', 1, 30 );
        }
    }

    /**
     * Plugin deactivation
     *
     * @since PBOOKING_SINCE
     */
    public function deactivate()
    {
        // Clear scheduled hooks
        wp_clear_scheduled_hook( 'nemtly_booking_hourly_reminder' );

        // Flush rewrite rules
        flush_rewrite_rules();

        // Notify the telemetry server of deactivation (non-blocking, fire-and-forget).
        if ( function_exists( 'wp_remote_post' ) ) {
            $token      = defined( 'NEMTLY_BOOKING_TELEMETRY_TOKEN' ) ? NEMTLY_BOOKING_TELEMETRY_TOKEN : '';
            $server_url = apply_filters( 'nemtly_booking_telemetry_server_url', 'https://feedio.sapayth.com/api/t/' . $token . '/' );
            $endpoint   = rtrim( $server_url, '/' ) . '/plugin-deactivate';

            wp_remote_post(
                $endpoint,
                [
                    'timeout'  => 2,
                    'blocking' => false,
                    'body'     => [
                        'url'         => home_url(),
                        'plugin_slug' => 'nemtly-booking',
                    ],
                ]
            );
        }
    }

    /**
     * Create database tables
     *
     * @since PBOOKING_SINCE
     */
    private function create_tables()
    {
        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();
        $table_name      = nemtly_booking_get_bookings_table();

        $sql = "CREATE TABLE {$table_name} (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            event_id bigint(20) NOT NULL,
            user_id bigint(20) DEFAULT NULL,
            booking_uuid varchar(36) NOT NULL,
            booking_status varchar(20) NOT NULL DEFAULT 'pending',
            attendee_name varchar(100) NOT NULL,
            attendee_email varchar(100) NOT NULL,
            attendee_phone varchar(20) DEFAULT NULL,
            booking_date date NOT NULL,
            booking_start datetime DEFAULT NULL,
            booking_end datetime DEFAULT NULL,
            booking_meta longtext DEFAULT NULL,
            created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY  (id),
            UNIQUE KEY booking_uuid (booking_uuid),
            KEY event_id (event_id),
            KEY user_id (user_id),
            KEY booking_status (booking_status),
            KEY booking_date (booking_date)
        ) $charset_collate;";

        $payments_table = nemtly_booking_get_payments_table();

        $sql .= "CREATE TABLE {$payments_table} (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            payable_id bigint(20) NOT NULL DEFAULT 0,
            payable_type varchar(50) NOT NULL DEFAULT 'booking',
            booking_id bigint(20) NOT NULL DEFAULT 0,
            transaction_id varchar(255) NOT NULL,
            amount decimal(10,2) NOT NULL,
            currency varchar(3) NOT NULL DEFAULT 'USD',
            status varchar(20) NOT NULL DEFAULT 'pending',
            gateway varchar(50) NOT NULL DEFAULT 'stripe',
            gateway_response longtext DEFAULT NULL,
            created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY  (id),
            KEY payable_id (payable_id),
            KEY payable_type (payable_type),
            KEY booking_id (booking_id),
            KEY transaction_id (transaction_id),
            KEY status (status)
        ) $charset_collate;";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta( $sql );
    }

    /**
     * Register custom post types
     *
     * @since PBOOKING_SINCE
     */
    public function register_post_types()
    {
        // Register Event post type
        register_post_type(
            'nemtly_event',
            [
                'labels'          => [
                    'name'               => __( 'Events', 'nemtly-booking' ),
                    'singular_name'      => __( 'Event', 'nemtly-booking' ),
                    'add_new'            => __( 'Add New Event', 'nemtly-booking' ),
                    'add_new_item'       => __( 'Add New Event', 'nemtly-booking' ),
                    'edit_item'          => __( 'Edit Event', 'nemtly-booking' ),
                    'new_item'           => __( 'New Event', 'nemtly-booking' ),
                    'view_item'          => __( 'View Event', 'nemtly-booking' ),
                    'search_items'       => __( 'Search Events', 'nemtly-booking' ),
                    'not_found'          => __( 'No events found', 'nemtly-booking' ),
                    'not_found_in_trash' => __( 'No events found in trash', 'nemtly-booking' ),
                ],
                'public'          => true,
                'show_ui'         => true,
                'show_in_menu'    => false,
                'show_in_rest'    => true,
                'supports'        => [ 'title', 'editor', 'custom-fields', 'thumbnail', 'excerpt' ],
                'capability_type' => 'post',
                'has_archive'     => true,
                'rewrite'         => [
                    'slug'       => 'events',
                    'with_front' => false,
                ],
                'menu_icon'       => 'dashicons-calendar-alt',
                'menu_position'   => 20,
            ]
        );

        // Expose event meta fields to the REST API so blocks can read them in the editor.
        $meta_fields = [
            Event_Creator::META_EVENT_DATE     => 'string',
            Event_Creator::META_EVENT_TIME     => 'string',
            Event_Creator::META_EVENT_TIMEZONE => 'string',
            Event_Creator::META_EVENT_TYPE     => 'string',
            Event_Creator::META_EVENT_DATE_UTC => 'string',
            Event_Creator::META_EVENT_TIME_UTC => 'string',
        ];

        foreach ( $meta_fields as $meta_key => $type ) {
            register_post_meta(
                'nemtly_event',
                $meta_key,
                [
                    'show_in_rest'  => true,
                    'single'        => true,
                    'type'          => $type,
                    'auth_callback' => '__return_true',
                ]
            );
        }
    }

    /**
     * Load event templates
     *
     * @since PBOOKING_SINCE
     *
     * @param string $template The template path.
     *
     * @return string
     */


    /**
     * Add event meta tags for SEO
     *
     * @since PBOOKING_SINCE
     */
    public function add_event_meta_tags()
    {
        global $post;

        if ( ! $post || 'nemtly_event' !== $post->post_type || ! is_singular( 'nemtly_event' ) ) {
            return;
        }

        $nemtly_booking_event_date = get_post_meta( $post->ID, '_nemtly_event_date', true );
        $nemtly_booking_event_time = get_post_meta( $post->ID, '_nemtly_event_time', true );
        $nemtly_booking_location   = get_post_meta( $post->ID, '_nemtly_location', true );

        ?>
        <!-- Open Graph Meta Tags -->
        <meta property="og:title" content="<?php echo esc_attr( get_the_title() ); ?>" />
        <meta property="og:description" content="<?php echo esc_attr( wp_strip_all_tags( get_the_excerpt() ) ); ?>" />
        <meta property="og:type" content="event" />
        <meta property="og:url" content="<?php echo esc_url( get_permalink() ); ?>" />
        <?php if ( has_post_thumbnail() ) : ?>
            <meta property="og:image" content="<?php echo esc_url( get_the_post_thumbnail_url( $post->ID, 'large' ) ); ?>" />
        <?php endif; ?>

        <!-- Event-specific Open Graph tags -->
        <?php if ( $nemtly_booking_event_date && $nemtly_booking_event_time ) : ?>
            <meta property="event:start_time"
                content="<?php echo esc_attr( $nemtly_booking_event_date . 'T' . $nemtly_booking_event_time . ':00' ); ?>" />
        <?php endif; ?>
        <?php if ( $nemtly_booking_location ) : ?>
            <meta property="event:location" content="<?php echo esc_attr( $nemtly_booking_location ); ?>" />
        <?php endif; ?>
		<?php
    }



    /**
     * Handle REST API authentication
     *
     * @since PBOOKING_SINCE
     *
     * @param \WP_Error|null $errors Authentication errors.
     *
     * @return \WP_Error|null
     */
    public function rest_authentication_handler( $errors )
    {
        // If there are already errors, return them
        if ( $errors ) {
            return $errors;
        }
        $request_uri = ! empty( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';

        // For our custom endpoints, ensure user is authenticated
        if ( strpos( $request_uri, '/wp-json/nemtly-booking/v1/' ) !== false ) {
            if ( ! is_user_logged_in() ) {
                return new \WP_Error(
                    'rest_forbidden',
                    __( 'Authentication required for this endpoint.', 'nemtly-booking' ),
                    [ 'status' => 401 ]
                );
            }
        }

        return null;
    }

    /**
     * Register custom taxonomies for events
     *
     * @since PBOOKING_SINCE
     *
     * @return void
     */
    public function register_taxonomies()
    {
        register_taxonomy(
            'nemtly_event_category',
            'nemtly_event',
            [
                'labels'            => [
                    'name'              => __( 'Event Categories', 'nemtly-booking' ),
                    'singular_name'     => __( 'Event Category', 'nemtly-booking' ),
                    'search_items'      => __( 'Search Categories', 'nemtly-booking' ),
                    'all_items'         => __( 'All Categories', 'nemtly-booking' ),
                    'parent_item'       => __( 'Parent Category', 'nemtly-booking' ),
                    'parent_item_colon' => __( 'Parent Category:', 'nemtly-booking' ),
                    'edit_item'         => __( 'Edit Category', 'nemtly-booking' ),
                    'update_item'       => __( 'Update Category', 'nemtly-booking' ),
                    'add_new_item'      => __( 'Add New Category', 'nemtly-booking' ),
                    'new_item_name'     => __( 'New Category Name', 'nemtly-booking' ),
                    'menu_name'         => __( 'Categories', 'nemtly-booking' ),
                    'not_found'         => __( 'No categories found.', 'nemtly-booking' ),
                    'no_terms'          => __( 'No categories', 'nemtly-booking' ),
                ],
                'hierarchical'      => true,
                'public'            => true,
                'show_ui'           => false,
                'show_in_menu'      => false,
                'show_in_rest'      => true,
                'rest_base'         => 'nemtly_event_category',
                'show_admin_column' => false,
                'rewrite'           => [
                    'slug'         => 'events/category',
                    'with_front'   => false,
                    'hierarchical' => true,
                ],
            ]
        );

        register_taxonomy(
            'nemtly_event_tag',
            'nemtly_event',
            [
                'labels'            => [
                    'name'                       => __( 'Event Tags', 'nemtly-booking' ),
                    'singular_name'              => __( 'Event Tag', 'nemtly-booking' ),
                    'search_items'               => __( 'Search Tags', 'nemtly-booking' ),
                    'popular_items'              => __( 'Popular Tags', 'nemtly-booking' ),
                    'all_items'                  => __( 'All Tags', 'nemtly-booking' ),
                    'edit_item'                  => __( 'Edit Tag', 'nemtly-booking' ),
                    'update_item'                => __( 'Update Tag', 'nemtly-booking' ),
                    'add_new_item'               => __( 'Add New Tag', 'nemtly-booking' ),
                    'new_item_name'              => __( 'New Tag Name', 'nemtly-booking' ),
                    'separate_items_with_commas' => __( 'Separate tags with commas', 'nemtly-booking' ),
                    'add_or_remove_items'        => __( 'Add or remove tags', 'nemtly-booking' ),
                    'choose_from_most_used'      => __( 'Choose from the most used tags', 'nemtly-booking' ),
                    'menu_name'                  => __( 'Tags', 'nemtly-booking' ),
                    'not_found'                  => __( 'No tags found.', 'nemtly-booking' ),
                    'no_terms'                   => __( 'No tags', 'nemtly-booking' ),
                ],
                'hierarchical'      => false,
                'public'            => true,
                'show_ui'           => false,
                'show_in_menu'      => false,
                'show_in_rest'      => true,
                'rest_base'         => 'nemtly_event_tag',
                'show_admin_column' => false,
                'rewrite'           => [
                    'slug'       => 'events/tag',
                    'with_front' => false,
                ],
            ]
        );
    }

    /**
     * Add meta_value to the allowed orderby parameters in REST API
     *
     * @param array $params Collection parameters.
     * @return array
     */
    public function add_rest_orderby_params( $params ) {
        $params['orderby']['enum'][] = 'meta_value';
        return $params;
    }

    /**
     * Handle meta_value sorting in REST API query
     *
     * @param array           $args    Key value array of query var to query value.
     * @param \WP_REST_Request $request The request used to generate the query.
     * @return array
     */
    public function handle_rest_orderby_params( $args, $request ) {
        $orderby = $request->get_param( 'orderby' );

        if ( 'meta_value' === $orderby ) {
            $args['meta_key'] = 'nemtly_event_date';
            $args['orderby']  = 'meta_value';
        }

        return $args;
    }
}
