<?php
/**
 * Contact Extractor Service
 * 
 * Extracts contact information (name, phone, email) from free text in chat messages.
 * Useful for automatically identifying leads from chat conversations.
 *
 * @package BoostBot
 * @since   1.3.0
 */

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

/**
 * Class BoostBot_Contact_Extractor
 *
 * Extracts contact information from free text.
 *
 * @since 1.3.0
 */
class BoostBot_Contact_Extractor {

    /**
     * Phone number patterns (Israeli and international).
     *
     * @var array
     */
    private $phone_patterns = array(
        '/(?:טל|טלפון|נייד|phone|mobile)?[:\s]*([0]?5[0-9]{8})/u',        // Israeli mobile: 05X-XXXXXXX
        '/(?:טל|טלפון|phone)?[:\s]*([0]?[2-9][0-9]{7,8})/u',               // Israeli landline
        '/\+?(972|1)?[- ]?([0-9]{1,2})[- ]?([0-9]{3})[- ]?([0-9]{4})/u',    // International format
    );

    /**
     * Email pattern.
     *
     * @var string
     */
    private $email_pattern = '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/u';

    /**
     * Name patterns (Hebrew and English).
     *
     * @var array
     */
    private $name_patterns = array(
        '/(?:שמי|שם|name|אני)[:\s]+([א-ת\w\s]{2,30})/u',       // "שמי דוד" or "name David"
        '/^([א-ת]{2,15})\s+([0-9]{9,10})/',                     // Name followed by phone at start
    );

    /**
     * Extract contact info from message.
     *
     * @param string $text The text to extract from.
     * @return array Contact information with confidence score.
     */
    public function extract( $text ) {
        $contact = array(
            'name'       => null,
            'phone'      => null,
            'email'      => null,
            'raw_text'   => $text,
            'confidence' => 0,
        );

        // Extract phone
        foreach ( $this->phone_patterns as $pattern ) {
            if ( preg_match( $pattern, $text, $match ) ) {
                // Pass the FULL match into normalize_phone(): the international pattern
                // splits the number across several capture groups (country code, area,
                // prefix, line), so $match[1] alone would drop most digits. normalize_phone()
                // strips non-digits, so leading label text in $match[0] is harmless.
                $phone = $this->normalize_phone( $match[0] );
                if ( $this->validate_phone( $phone ) ) {
                    $contact['phone'] = $phone;
                    $contact['confidence'] += 40;
                    break;
                }
            }
        }

        // Extract email
        if ( preg_match( $this->email_pattern, $text, $match ) ) {
            $contact['email'] = strtolower( $match[0] );
            // A validated email alone is sufficient to qualify as a lead (weight == threshold).
            $contact['confidence'] += 40;
        }

        // Extract name from explicit patterns
        foreach ( $this->name_patterns as $pattern ) {
            if ( preg_match( $pattern, $text, $match ) ) {
                $name = trim( $match[1] );
                // Clean up the name - remove phone numbers if accidentally captured
                $name = preg_replace( '/[0-9\-\+]+/', '', $name );
                $name = trim( $name );
                
                if ( mb_strlen( $name ) >= 2 && mb_strlen( $name ) <= 30 ) {
                    $contact['name'] = $name;
                    $contact['confidence'] += 30;
                    break;
                }
            }
        }

        // Try to extract name from text before phone number (if no explicit name found)
        if ( ! $contact['name'] && $contact['phone'] ) {
            $before_phone = preg_replace( '/[0-9\-\+\s]{8,}.*$/', '', $text );
            $before_phone = trim( $before_phone );
            
            // Remove common prefixes
            $before_phone = preg_replace( '/^(שמי|שם|אני|הי|היי|שלום)\s*/u', '', $before_phone );
            $before_phone = trim( $before_phone );
            
            if ( mb_strlen( $before_phone ) >= 2 && mb_strlen( $before_phone ) <= 30 ) {
                // Check if it looks like a name (Hebrew or English letters only)
                if ( preg_match( '/^[א-תa-zA-Z\s]+$/u', $before_phone ) ) {
                    $contact['name'] = $before_phone;
                    $contact['confidence'] += 20;
                }
            }
        }

        return $contact;
    }

    /**
     * Normalize phone number to standard format.
     *
     * @param string $phone The phone number to normalize.
     * @return string Normalized phone number.
     */
    private function normalize_phone( $phone ) {
        // Remove all non-digits
        $phone = preg_replace( '/[^0-9]/', '', $phone );

        // Ensure Israeli prefix
        if ( strlen( $phone ) === 9 && $phone[0] === '5' ) {
            $phone = '0' . $phone;
        }

        // Convert 972 to 0
        if ( strpos( $phone, '972' ) === 0 ) {
            $phone = '0' . substr( $phone, 3 );
        }

        return $phone;
    }

    /**
     * Validate phone number.
     *
     * @param string $phone The phone number to validate.
     * @return bool True if valid.
     */
    private function validate_phone( $phone ) {
        // Israeli mobile: 05X-XXXXXXX (10 digits)
        if ( preg_match( '/^05[0-9]{8}$/', $phone ) ) {
            return true;
        }

        // Israeli landline: 0X-XXXXXXX (9-10 digits)
        if ( preg_match( '/^0[2-9][0-9]{7,8}$/', $phone ) ) {
            return true;
        }

        return false;
    }

    /**
     * Check if text likely contains contact info.
     *
     * @param string $text The text to check.
     * @return bool True if contact info is found.
     */
    public function has_contact_info( $text ) {
        $extracted = $this->extract( $text );
        // A validated phone (weight 40) OR a validated email (weight 40) is enough.
        return $extracted['confidence'] >= 40;
    }

    /**
     * Get the confidence threshold for saving as lead.
     *
     * @return int The minimum confidence score to save as lead.
     */
    public function get_confidence_threshold() {
        return 40;
    }
}





