<?php

namespace WeDevs\Wpuf\Pro\Integrations\Events_Calendar\Compatibility;

/**
 * TEC Compatibility Handler (Pro, v6+)
 *
 * Handles The Events Calendar v6.x API calls and functionality
 *
 * @since 4.1.8
 */
class TEC_Compatibility {
    /**
     * Convert form data directly to ORM format
     *
     * @since 4.1.8
     *
     * @param array $form_data
     * @param array $meta_vars
     *
     * @return array|bool
     */
    private function convert_form_data_to_orm_format( $form_data, $meta_vars = [] ) {
        $orm_args = [];
        // Merge form data with meta vars for comprehensive data access
        $all_data = array_merge( $form_data, $meta_vars );

        // Whitelist of event meta fields to extract from $_POST
        $event_meta_keys = [
            '_EventStartDate',
            '_EventEndDate',
            '_EventAllDay',
            'venue',
            '_EventVenueID',
            'venue_name',
            'venue_address',
            'venue_phone',
            'venue_website',
            'organizer',
            '_EventOrganizerID',
            'organizer_name',
            'organizer_phone',
            'organizer_website',
            'organizer_email',
            '_EventURL',
            '_EventCurrencySymbol',
            '_EventCost',
            '_EventShowMap',
            '_EventShowMapLink',
            '_EventHideFromUpcoming',
            '_EventDuration',
            '_EventCurrencyPosition',
            '_EventTimezone',
            'featured_image',
            'EventFeatured',
            'EventSticky',
        ];

        // Extract event meta fields from $_POST
        $event_meta_data = [];
        foreach ( $event_meta_keys as $key ) {
            if ( isset( $_POST[ $key ] ) ) {
                $event_meta_data[ $key ] = $_POST[ $key ];
            }
        }

        // Extract post-related fields from $form_data/$all_data
        $post_keys = [
            'post_title',
            'post_content',
            'post_excerpt',
            'tags',
            'tags_input',  // Also check for tags_input which is what WPUF actually sends
            'tribe_events_cat',
        ];
        $post_data = [];
        foreach ( $post_keys as $key ) {
            if ( isset( $form_data[ $key ] ) ) {
                $post_data[ $key ] = $form_data[ $key ];
            }
        }

        // Merge post fields from $post_data and event meta fields from $_POST
        $all_event_data = array_merge( $post_data, $event_meta_data );

        /**
         * Opportunity to modify form data before converting to TEC ORM format
         *
         * This filter allows developers to modify the raw form data before it's processed
         * into TEC ORM format. Useful for data validation, transformation, or integration
         * with custom form fields.
         *
         * @since 4.1.8
         *
         * @param array $all_event_data  The merged form data and meta variables
         * @param array $form_data The original form data from WPUF
         * @param array $meta_vars The original meta variables from WPUF
         */
        $all_event_data = apply_filters( 'wpuf_tec_before_convert_form_data', $all_event_data, $form_data, $meta_vars );

        // Required fields
        if ( ! empty( $all_event_data['post_title'] ) ) {
            $orm_args['title'] = sanitize_text_field( $all_event_data['post_title'] );
        }
        // Map basic fields
        if ( ! empty( $all_event_data['post_content'] ) ) {
            $orm_args['description'] = wp_kses_post( $all_event_data['post_content'] );
        }
        if ( ! empty( $all_event_data['post_excerpt'] ) ) {
            $orm_args['excerpt'] = sanitize_textarea_field( $all_event_data['post_excerpt'] );
        }
        // Handle date fields - these are critical for TEC ORM
        // Use TEC ORM field aliases instead of meta field names
        if ( ! empty( $all_event_data['_EventStartDate'] ) ) {
            $orm_args['start_date'] = $this->format_date_for_tec( $all_event_data['_EventStartDate'] );
        } else {
            // Fallback: create a default start date if none provided
            $default_start          = current_time( 'Y-m-d H:i:s' );
            $orm_args['start_date'] = $default_start;
        }
        if ( ! empty( $all_event_data['_EventEndDate'] ) ) {
            $end_date = $this->format_date_for_tec( $all_event_data['_EventEndDate'] );
            if ( $end_date ) {
                // Enforce Y-m-d H:i:s format
                $dt = \DateTime::createFromFormat( 'Y-m-d H:i:s', $end_date );
                if ( $dt ) {
                    $orm_args['end_date'] = $dt->format( 'Y-m-d H:i:s' );
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } else {
            // Fallback: create a default end date if none provided
            if ( ! empty( $orm_args['start_date'] ) ) {
                $default_end          = date(
                    'Y-m-d H:i:s', strtotime( $orm_args['start_date'] ) + 3600
                ); // 1 hour later
                $orm_args['end_date'] = $default_end;
            }
        }
        // Add UTC dates for TEC v6 compatibility using ORM field aliases
        if ( ! empty( $orm_args['start_date'] ) ) {
            $timezone = isset( $orm_args['timezone'] ) ? $orm_args['timezone'] : 'UTC';
            try {
                $start_datetime             = new \DateTime( $orm_args['start_date'], new \DateTimeZone( $timezone ) );
                $orm_args['start_date_utc'] = $start_datetime->setTimezone( new \DateTimeZone( 'UTC' ) )->format(
                    'Y-m-d H:i:s'
                );
            } catch ( \Exception $e ) {
                // Fallback: use the same time as UTC
                $orm_args['start_date_utc'] = $orm_args['start_date'];
            }
        }
        if ( ! empty( $orm_args['end_date'] ) ) {
            $timezone = isset( $orm_args['timezone'] ) ? $orm_args['timezone'] : 'UTC';
            try {
                $end_datetime             = new \DateTime( $orm_args['end_date'], new \DateTimeZone( $timezone ) );
                $orm_args['end_date_utc'] = $end_datetime->setTimezone( new \DateTimeZone( 'UTC' ) )->format(
                    'Y-m-d H:i:s'
                );
            } catch ( \Exception $e ) {
                // Fallback: use the same time as UTC
                $orm_args['end_date_utc'] = $orm_args['end_date'];
            }
        }
        // Handle all-day events using ORM field alias
        if ( ! empty( $all_event_data['_EventAllDay'] ) ) {
            $is_all_day = ! empty( $all_event_data['_EventAllDay'] ) ? $all_event_data['_EventAllDay'] : 'no';
            $orm_args['all_day'] = $is_all_day;
            // For all-day events, if no end date is provided, set it to the same day
            if ( $is_all_day && ! empty( $orm_args['start_date'] ) && empty( $orm_args['end_date'] ) ) {
                $start_date = $this->format_date_for_tec( $all_event_data['_EventStartDate'] );
                if ( $start_date ) {
                    // Set end date to same day at 23:59:59
                    $end_date             = date( 'Y-m-d 23:59:59', strtotime( $start_date ) );
                    $orm_args['end_date'] = $end_date;
                }
            }
        }
        if ( isset( $all_event_data['EventFeatured'] ) ) {
            $orm_args['featured'] = tribe_is_truthy( $all_event_data['EventFeatured'] );
        }
        if ( isset( $all_event_data['EventSticky'] ) ) {
            $orm_args['sticky'] = tribe_is_truthy( $all_event_data['EventSticky'] );
        }
        // Map cost field (int or float) - handle properly for ORM API
        if ( ! empty( $all_event_data['_EventCost'] ) ) {
            $cost = sanitize_text_field( $all_event_data['_EventCost'] );
            // Remove any currency symbols and clean the cost value
            $cost = preg_replace( '/[^0-9.]/', '', $cost );
            if ( is_numeric( $cost ) && floatval( $cost ) > 0 ) {
                $orm_args['cost'] = floatval( $cost );
            }
        }
        // Map currency fields using ORM field aliases
        if ( ! empty( $all_event_data['_EventCurrencySymbol'] ) ) {
            $orm_args['currency_symbol'] = sanitize_text_field( $all_event_data['_EventCurrencySymbol'] );
        }
        if ( ! empty( $all_event_data['_EventCurrencyPosition'] ) ) {
            $orm_args['currency_position'] = sanitize_text_field( $all_event_data['_EventCurrencyPosition'] );
        }
        // Map timezone
        if ( ! empty( $all_event_data['_EventTimezone'] ) ) {
            $timezone = sanitize_text_field( $all_event_data['_EventTimezone'] );
            // Validate timezone
            if ( in_array( $timezone, timezone_identifiers_list() ) ) {
                $orm_args['timezone'] = $timezone;
            } else {
                // Use default timezone as fallback
                $orm_args['timezone'] = wp_timezone_string();
            }
        } else {
            // Use default timezone if none provided
            $orm_args['timezone'] = wp_timezone_string();
        }
        // Ensure timezone is valid for TEC
        if ( ! in_array( $orm_args['timezone'], timezone_identifiers_list() ) ) {
            $orm_args['timezone'] = 'UTC';
        }
        // Map URL field using ORM field alias
        if ( ! empty( $all_event_data['_EventURL'] ) ) {
            $orm_args['url'] = esc_url_raw( $all_event_data['_EventURL'] );
        }
        // Map image field
        if ( ! empty( $all_event_data['featured_image'] ) ) {
            $orm_args['image'] = intval( $all_event_data['featured_image'] );
        }
        // Map presentation fields using ORM field aliases
        if ( ! empty( $all_event_data['_EventShowMap'] ) ) {
            $show_map             = is_array( $all_event_data['_EventShowMap'] ) && in_array(
                    '1', $all_event_data['_EventShowMap']
                );
            $orm_args['show_map'] = $show_map;
        }
        if ( ! empty( $all_event_data['_EventShowMapLink'] ) ) {
            $show_map_link             = is_array( $all_event_data['_EventShowMapLink'] ) && in_array(
                    '1', $all_event_data['_EventShowMapLink']
                );
            $orm_args['show_map_link'] = $show_map_link;
        }
        if ( ! empty( $all_event_data['_EventHideFromUpcoming'] ) ) {
            $hide_from_upcoming             = is_array( $all_event_data['_EventHideFromUpcoming'] ) && in_array(
                    '1', $all_event_data['_EventHideFromUpcoming']
                );
            $orm_args['hide_from_upcoming'] = $hide_from_upcoming;
        }
        // Map duration if available
        if ( ! empty( $all_event_data['_EventDuration'] ) ) {
            $orm_args['duration'] = intval( $all_event_data['_EventDuration'] );
        }
        // Map tags if available - check both 'tags' and 'tags_input'
        if ( ! empty( $all_event_data['tags_input'] ) ) {
            // WPUF already processed tags into tags_input format (array)
            $orm_args['tags_input'] = $all_event_data['tags_input'];
        } elseif ( ! empty( $all_event_data['tags'] ) ) {
            // Handle tags - can be string (comma-separated) or array
            if ( is_string( $all_event_data['tags'] ) ) {
                // Convert comma-separated string to array
                $tags = array_map( 'trim', explode( ',', $all_event_data['tags'] ) );
                $orm_args['tags_input'] = $tags;
            } else if ( is_array( $all_event_data['tags'] ) ) {
                $orm_args['tags_input'] = $all_event_data['tags'];
            }
        }
        /**
         * Opportunity to modify TEC ORM arguments after conversion from form data
         *
         * This filter allows developers to modify the ORM arguments before they're validated
         * and saved. Useful for custom field mapping, data transformation, or integration
         * with third-party services.
         *
         * @since 4.1.8
         *
         * @param array $orm_args  The ORM arguments ready for TEC API
         * @param array $all_event_data  The original merged form data
         * @param array $form_data The original form data from WPUF
         * @param array $meta_vars The original meta variables from WPUF
         */
        $orm_args = apply_filters( 'wpuf_tec_after_convert_form_data', $orm_args, $all_event_data, $form_data, $meta_vars );

        return $orm_args;
    }

    /**
     * Save event using TEC v6 ORM API
     *
     * @since 4.1.8
     *
     * @param array $postarr       The post array (title, content, etc.)
     * @param array $meta_vars     The meta fields from the form
     * @param int   $form_id       The WPUF form ID
     * @param array $form_settings The WPUF form settings
     *
     * @return int|false The created event post ID on success, 0 or false on failure
     */
    public function save_event( $postarr, $meta_vars, $form_id, $form_settings ) {
        // 1. Create or update venue if venue data is present
        $venue_id = $this->create_or_update_venue();

        // 2. Create or update organizer if organizer data is present
        $organizer_id = $this->create_or_update_organizer();

        // 3. Convert WPUF data to TEC ORM format
        $args = $this->convert_form_data_to_orm_format( $postarr, $meta_vars );

        if ( ! empty( $venue_id ) ) {
            $args['venue'] = $venue_id;
        }

        if ( ! empty( $organizer_id ) ) {
            $args['organizer'] = $organizer_id;
        }

        if ( empty( $args ) || ! is_array( $args ) ) {
            return 0;
        }
        // Remove ID if present (should not be set for new posts)
        if ( isset( $args['ID'] ) ) {
            unset( $args['ID'] );
        }
        /**
         * Opportunity to modify TEC ORM arguments before creating the event
         *
         * This filter allows developers to modify the final ORM arguments before the event
         * is created via TEC's API. Useful for last-minute data validation, transformation,
         * or integration with external services.
         *
         * @since 4.1.8
         *
         * @param array $args          The ORM arguments ready for TEC API
         * @param array $postarr       The original WordPress post array
         * @param array $meta_vars     The original meta variables from WPUF
         * @param int   $form_id       The WPUF form ID
         * @param array $form_settings The WPUF form settings
         */
        $args = apply_filters( 'wpuf_tec_before_create_event', $args, $postarr, $meta_vars, $form_id, $form_settings );
        // Call the TEC ORM API
        try {
            if ( function_exists( 'tribe_events' ) ) {
                $event = tribe_events()->set_args( $args )->create();

                if ( $event instanceof \WP_Post ) {
                    $post_status = ! empty( $form_settings['post_status'] ) ? $form_settings['post_status'] : 'draft';

                    // Temporarily remove TEC hooks that clear venue/organizer
                    remove_action('save_post_tribe_events', array(\Tribe__Events__Main::instance(), 'addEventMeta'), 1);
                    remove_action('publish_tribe_events', array(\Tribe__Events__Main::instance(), 'publishAssociatedTypes'), 10);

                    $update_args = [
                        'ID'          => $event->ID,
                        'post_status' => $post_status,
                    ];

                    wp_update_post( $update_args );

                    // Add tags if they exist - use wp_set_post_tags for better reliability
                    if ( ! empty( $args['tags_input'] ) ) {
                        wp_set_post_tags( $event->ID, $args['tags_input'], false );
                    }

                    // Re-add the hooks
                    add_action('save_post_tribe_events', array(\Tribe__Events__Main::instance(), 'addEventMeta'), 1, 2);
                    add_action('publish_tribe_events', array(\Tribe__Events__Main::instance(), 'publishAssociatedTypes'), 10, 2);

                    // Now safely set the venue and organizer
                    if (!empty($args['venue'])) {
                        update_post_meta($event->ID, '_EventVenueID', $args['venue']);
                        // Store in a backup meta for later restoration if needed
                        update_post_meta($event->ID, '_wpuf_venue_id', $args['venue']);
                    }
                    if (!empty($args['organizer'])) {
                        update_post_meta($event->ID, '_EventOrganizerID', $args['organizer']);
                        // Store in a backup meta for later restoration if needed
                        update_post_meta($event->ID, '_wpuf_organizer_id', $args['organizer']);
                    }

                    // Hook to restore venue/organizer after all WPUF processing
                    add_action('wpuf_add_post_after_insert', function($post_id) use ($event, $args) {
                        if ($post_id == $event->ID) {
                            if (!empty($args['venue'])) {
                                update_post_meta($post_id, '_EventVenueID', $args['venue']);
                            }
                            if (!empty($args['organizer'])) {
                                update_post_meta($post_id, '_EventOrganizerID', $args['organizer']);
                            }
                        }
                    }, 999, 1);
                    /**
                     * Opportunity to perform actions after event creation
                     *
                     * This action allows developers to perform additional operations after
                     * an event has been successfully created. Useful for notifications,
                     * integrations, or custom post-processing.
                     *
                     * @since 4.1.8
                     *
                     * @param int   $event_id      The created event post ID
                     * @param array $args          The ORM arguments used to create the event
                     * @param array $postarr       The original WordPress post array
                     * @param array $meta_vars     The original meta variables from WPUF
                     * @param int   $form_id       The WPUF form ID
                     * @param array $form_settings The WPUF form settings
                     */
                    do_action(
                        'wpuf_tec_after_create_event', $event->ID, $args, $postarr, $meta_vars, $form_id, $form_settings
                    );

                    return $event->ID;
                } else {
                    return 0;
                }
            } else {
                return 0;
            }
        } catch ( \Exception $e ) {
            return 0;
        }
    }

    /**
     * Create or update venue based on meta_vars
     *
     * @param array $meta_vars
     * @param int   $form_id
     * @param array $form_settings
     * @return int|false Venue post ID or false if not created/updated
     */
    protected function create_or_update_venue() {
        // Use the new Venue_Handler to create or update the venue
        if ( ! class_exists( '\WeDevs\Wpuf\Pro\Integrations\Events_Calendar\Handlers\Venue_Handler' ) ) {
            require_once dirname(__DIR__) . '/Handlers/Venue_Handler.php';
        }
        return \WeDevs\Wpuf\Pro\Integrations\Events_Calendar\Handlers\Venue_Handler::create_or_update_venue_from_post();
    }

    /**
     * Create or update organizer based on meta_vars
     *
     * @param array $meta_vars
     * @param int   $form_id
     * @param array $form_settings
     * @return int|false Organizer post ID or false if not created/updated
     */
    protected function create_or_update_organizer() {
        // Use the new Organizer_Handler to create or update the organizer
        if ( ! class_exists( '\WeDevs\Wpuf\Pro\Integrations\Events_Calendar\Handlers\Organizer_Handler' ) ) {
            require_once dirname(__DIR__) . '/Handlers/Organizer_Handler.php';
        }
        return \WeDevs\Wpuf\Pro\Integrations\Events_Calendar\Handlers\Organizer_Handler::create_or_update_organizer_from_post();
    }

    /**
     * Format date for TEC ORM
     *
     * @since 4.1.8
     *
     * @param string $date_string
     *
     * @return string|false
     */
    public function format_date_for_tec( $date_string ) {
        if ( empty( $date_string ) ) {
            return false;
        }
        try {
            // First try TEC's build_date_object function
            if ( class_exists( 'Tribe__Date_Utils' ) ) {
                $date_object = \Tribe__Date_Utils::build_date_object( $date_string );
                if ( $date_object ) {
                    return $date_object->format( \Tribe__Date_Utils::DBDATETIMEFORMAT );
                }
            }

            return false;
        } catch ( \Exception $e ) {
            return false;
        }
    }

    /**
     * Check if TEC v6 is active
     *
     * @since 4.1.8
     *
     * @return bool
     */
    public function is_active() {
        return class_exists( 'Tribe__Events__Main' ) && function_exists( 'tribe_events' );
    }
}
