<?php
/**
 * CRM Webhook Service
 *
 * Sends data to external CRM systems via webhooks.
 *
 * @package BoostBot
 * @since   1.0.0
 */

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Class BoostBot_CRM_Webhook_Service
 *
 * Service for sending webhook notifications to CRM systems.
 */
class BoostBot_CRM_Webhook_Service {

    /**
     * Webhook URL.
     *
     * @var string
     */
    private $webhook_url;

    /**
     * API Key for authentication.
     *
     * @var string
     */
    private $api_key;

    /**
     * Constructor.
     */
    public function __construct() {
        $this->webhook_url = BoostBot_Settings::get( 'crm_webhook_url', '' );
        // Prefer explicit webhook api key, but keep legacy fallback for older installs.
        $this->api_key     = BoostBot_Settings::get( 'crm_webhook_api_key', '' );
        if ( empty( $this->api_key ) ) {
            $this->api_key = BoostBot_Settings::get( 'crm_api_key', '' );
        }
    }

    /**
     * Check if webhook is configured.
     *
     * @return bool
     */
    public function is_configured(): bool {
        return ! empty( $this->webhook_url );
    }

    /**
     * Check if outgoing webhooks are enabled.
     *
     * @return bool
     */
    public function is_enabled(): bool {
        return (bool) BoostBot_Settings::get( 'crm_webhook_enabled', false );
    }

    /**
     * Check if an event type is enabled.
     *
     * @param string $event_type Event type.
     * @return bool
     */
    public function is_event_enabled( string $event_type ): bool {
        $events = BoostBot_Settings::get( 'crm_webhook_events', array() );
        if ( ! is_array( $events ) ) {
            $events = array();
        }
        if ( array_key_exists( $event_type, $events ) ) {
            return (bool) $events[ $event_type ];
        }
        // Unknown events default to enabled to avoid silent drops when new events are introduced.
        return true;
    }

    /**
     * Send data to CRM webhook.
     *
     * @param string $event_type Event type.
     * @param array  $data       Event data.
     * @param bool   $blocking   Whether to wait for the response. Fire-and-forget
     *                           event hooks pass false so the visitor-facing request
     *                           is never delayed by the outbound HTTP call.
     * @return bool|WP_Error True on success, WP_Error on failure.
     */
    public function send( string $event_type, array $data, bool $blocking = true ) {
        if ( ! $this->is_enabled() ) {
            return new WP_Error( 'disabled', __( 'CRM webhook is disabled', 'boostbot' ) );
        }

        if ( ! $this->is_configured() ) {
            return new WP_Error( 'not_configured', __( 'CRM webhook not configured', 'boostbot' ) );
        }

        if ( ! $this->is_event_enabled( $event_type ) ) {
            return new WP_Error( 'event_disabled', __( 'Webhook event disabled', 'boostbot' ) );
        }

        $payload = array(
            'event'     => $event_type,
            'timestamp' => gmdate( 'Y-m-d\TH:i:s\Z' ),
            'site_url'  => home_url(),
            'data'      => $data,
        );

        $headers = array(
            'Content-Type' => 'application/json',
        );

        // Add authentication.
        if ( ! empty( $this->api_key ) ) {
            $headers['X-API-Key']      = $this->api_key;
            $headers['Authorization']  = 'Bearer ' . $this->api_key;
        }

        $response = wp_remote_post(
            $this->webhook_url,
            array(
                'headers'  => $headers,
                'body'     => wp_json_encode( $payload ),
                // Non-blocking sends use a short timeout and never wait for a response.
                'timeout'  => $blocking ? 15 : 1,
                'blocking' => $blocking,
            )
        );

        // Log the webhook.
        $this->log_webhook( $event_type, $payload, $response );

        // Fire-and-forget: a non-blocking request has no meaningful response to inspect.
        if ( ! $blocking ) {
            return true;
        }

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

        $response_code = wp_remote_retrieve_response_code( $response );

        if ( $response_code < 200 || $response_code >= 300 ) {
            return new WP_Error(
                'webhook_failed',
                /* translators: %d: HTTP response status code */
                sprintf( __( 'Webhook returned status %d', 'boostbot' ), $response_code )
            );
        }

        return true;
    }

    /**
     * Send lead created event.
     *
     * @param array $lead_data Lead data.
     * @return bool|WP_Error
     */
    public function send_lead( array $lead_data ) {
        // Non-blocking: fired on the chat/lead hot path, must not delay the visitor reply.
        return $this->send( 'lead_created', $lead_data, false );
    }

    /**
     * Send booking created event.
     *
     * @param array $booking_data Booking data.
     * @return bool|WP_Error
     */
    public function send_booking( array $booking_data ) {
        // Non-blocking: fired when a meeting is booked, on the visitor-facing path.
        return $this->send( 'booking_created', $booking_data, false );
    }

    /**
     * Send form submission event.
     *
     * @param array $form_data Form data.
     * @return bool|WP_Error
     */
    public function send_form_submission( array $form_data ) {
        // Non-blocking: fired on form submit, on the visitor-facing path.
        return $this->send( 'form_submitted', $form_data, false );
    }

    /**
     * Send conversation started event.
     *
     * @param array $conversation_data Conversation data.
     * @return bool|WP_Error
     */
    public function send_conversation_started( array $conversation_data ) {
        // Non-blocking: fired when a conversation starts, on the visitor-facing path.
        return $this->send( 'conversation_started', $conversation_data, false );
    }

    /**
     * Send conversation ended event.
     *
     * @param array $conversation_data Conversation data.
     * @return bool|WP_Error
     */
    public function send_conversation_ended( array $conversation_data ) {
        // Non-blocking: fired when a conversation ends, on the visitor-facing path.
        return $this->send( 'conversation_ended', $conversation_data, false );
    }

    /**
     * Log webhook for debugging.
     *
     * @param string                $event_type Event type.
     * @param array                 $payload    Sent payload.
     * @param array|WP_Error        $response   Response.
     */
    private function log_webhook( string $event_type, array $payload, $response ) {
        // Only log in debug mode.
        if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
            return;
        }

        $log_entry = array(
            'event_type' => $event_type,
            'payload'    => $payload,
            'timestamp'  => current_time( 'mysql' ),
        );

        if ( is_wp_error( $response ) ) {
            $log_entry['success']       = false;
            $log_entry['error_code']    = $response->get_error_code();
            $log_entry['error_message'] = $response->get_error_message();
        } else {
            $log_entry['success']       = true;
            $log_entry['response_code'] = wp_remote_retrieve_response_code( $response );
            $log_entry['response_body'] = wp_remote_retrieve_body( $response );
        }

        // Log to BoostBot logger if available.
        if ( class_exists( 'BoostBot_Logger' ) ) {
            if ( $log_entry['success'] ) {
                BoostBot_Logger::info( 'CRM Webhook sent', $log_entry );
            } else {
                BoostBot_Logger::error( 'CRM Webhook failed', $log_entry );
            }
        }
    }

    /**
     * Test webhook connection.
     *
     * @return array Test result with 'success' and 'message'.
     */
    public function test_connection(): array {
        if ( ! $this->is_configured() ) {
            return array(
                'success' => false,
                'message' => __( 'Webhook URL not configured', 'boostbot' ),
            );
        }

        if ( ! $this->is_enabled() ) {
            return array(
                'success' => false,
                'message' => __( 'Webhook is disabled', 'boostbot' ),
            );
        }

        $result = $this->send(
            'test',
            array(
                'message' => 'This is a test webhook from BoostBot',
            )
        );

        if ( is_wp_error( $result ) ) {
            return array(
                'success' => false,
                'message' => $result->get_error_message(),
            );
        }

        return array(
            'success' => true,
            'message' => __( 'Webhook is working correctly', 'boostbot' ),
        );
    }

    /**
     * Register WordPress hooks for outgoing webhook events.
     *
     * @return void
     */
    public static function register_hooks(): void {
        // Leads (created via widgets or extraction) should trigger boostbot_lead_created.
        add_action(
            'boostbot_lead_created',
            function ( $lead_id, $lead_data = array(), $context = array() ) {
                $service = new self();
                if ( ! $service->is_enabled() || ! $service->is_configured() ) {
                    return;
                }

                // Fetch fresh lead from DB to ensure complete data
                $lead_model = new BoostBot_Lead_Model();
                $lead = $lead_model->get( absint( $lead_id ) );
                
                // Decode JSON fields for complete payload
                $form_data = array();
                $metadata  = array();
                if ( $lead ) {
                    $form_data = ! empty( $lead->form_data ) ? json_decode( $lead->form_data, true ) : array();
                    $metadata  = ! empty( $lead->metadata ) ? json_decode( $lead->metadata, true ) : array();
                }

                $payload = array(
                    'lead_id'         => absint( $lead_id ),
                    'name'            => $lead ? $lead->name : ( $lead_data['name'] ?? '' ),
                    'email'           => $lead ? $lead->email : ( $lead_data['email'] ?? '' ),
                    'phone'           => $lead ? $lead->phone : ( $lead_data['phone'] ?? '' ),
                    'company'         => $lead ? $lead->company : ( $lead_data['company'] ?? '' ),
                    'lead_status'     => $lead ? $lead->lead_status : ( $lead_data['lead_status'] ?? 'new' ),
                    'lead_score'      => $lead ? $lead->lead_score : ( $lead_data['lead_score'] ?? 0 ),
                    'source_page'     => $lead ? $lead->source_page : ( $lead_data['source_page'] ?? '' ),
                    'form_data'       => $form_data,
                    'metadata'        => $metadata,
                    'widget_id'       => $metadata['widget_id'] ?? ( $context['widget_id'] ?? null ),
                    'widget_type'     => $metadata['widget_type'] ?? ( $context['widget_type'] ?? null ),
                    'bot_id'          => $metadata['bot_id'] ?? ( $context['bot_id'] ?? null ),
                    'page_url'        => $metadata['page_url'] ?? ( $lead ? $lead->source_page : '' ),
                    'conversation_id' => $lead ? $lead->conversation_id : ( $context['conversation_id'] ?? '' ),
                    'visitor_id'      => $lead ? $lead->visitor_id : ( $context['visitor_id'] ?? '' ),
                    'created_at'      => $lead ? $lead->created_at : current_time( 'mysql' ),
                    'context'         => is_array( $context ) ? $context : array(),
                );

                $service->send_lead( $payload );
            },
            10,
            3
        );

        // Conversation start.
        add_action(
            'boostbot_conversation_started',
            function ( $conversation ) {
                $service = new self();
                if ( ! $service->is_enabled() || ! $service->is_configured() ) {
                    return;
                }

                $data = is_object( $conversation ) ? (array) $conversation : ( is_array( $conversation ) ? $conversation : array() );
                
                // Decode context_data to extract page info
                $context_data = array();
                if ( ! empty( $data['context_data'] ) ) {
                    $context_data = is_string( $data['context_data'] ) 
                        ? json_decode( $data['context_data'], true ) 
                        : $data['context_data'];
                }
                
                // Expose page_url and page_title at top level
                $data['page_url']   = $context_data['page_url'] ?? $context_data['url'] ?? null;
                $data['page_title'] = $context_data['page_title'] ?? $context_data['title'] ?? null;
                $data['referrer']   = $context_data['referrer'] ?? null;
                
                $service->send_conversation_started( $data );
            },
            10,
            1
        );

        // Meeting booked.
        add_action(
            'boostbot_meeting_booked',
            function ( $meeting ) {
                $service = new self();
                if ( ! $service->is_enabled() || ! $service->is_configured() ) {
                    return;
                }

                $data = is_object( $meeting ) ? (array) $meeting : ( is_array( $meeting ) ? $meeting : array() );
                
                // Decode custom_fields to extract page info
                $custom_fields = array();
                if ( ! empty( $data['custom_fields'] ) ) {
                    $custom_fields = is_string( $data['custom_fields'] ) 
                        ? json_decode( $data['custom_fields'], true ) 
                        : $data['custom_fields'];
                }
                
                // Expose page_url at top level
                $data['page_url']      = $custom_fields['page_url'] ?? null;
                $data['page_title']    = $custom_fields['page_title'] ?? null;
                $data['custom_fields'] = $custom_fields;
                
                $service->send_booking( $data );
            },
            10,
            1
        );
    }
}







