<?php

namespace PloverCRM\Core\CRM\Providers;

use PloverCRM\Common\CrmUserManager;
use PloverCRM\Core\CRM\CRMProviderInterface;
use PloverCRM\Modules\NativeCRM\CustomFieldsManager;
use PloverCRM\Modules\NativeCRM\Services\Logger;
use PloverCRM\Core\Helpers\DateTimeHelper;

/**
 * Native CRM Provider Implementation
 * 
 * Implements CRM operations for the built-in CRM system
 */
class NativeCRMProvider implements CRMProviderInterface
{
    /**
     * Standard contact fields mapping: field_key => meta_key
     */
    const STANDARD_FIELDS = [
        'email' => 'plover_crm_email',
        'first_name' => 'plover_crm_first_name',
        'last_name' => 'plover_crm_last_name',
        'phone' => 'plover_crm_phone',
        'city' => 'plover_crm_city',
        'state' => 'plover_crm_state',
        'country' => 'plover_crm_country',
        'postal_code' => 'plover_crm_postal_code',
        'source' => 'plover_crm_source',
    ];

    /**
     * Standard field labels for display
     */
    const STANDARD_FIELD_LABELS = [
        'email' => 'Email',
        'first_name' => 'First Name',
        'last_name' => 'Last Name',
        'phone' => 'Phone',
        'city' => 'City',
        'state' => 'State',
        'country' => 'Country',
        'postal_code' => 'Postal Code',
    ];

    /**
     * @var CustomFieldsManager
     */
    private $customFieldsManager;

    /**
     * @var Logger
     */
    private $logger;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->customFieldsManager = new CustomFieldsManager();
    }

    /**
     * Get logger instance
     */
    private function getLogger(): Logger
    {
        if (!$this->logger) {
            $this->logger = new Logger();
        }
        return $this->logger;
    }

    /**
     * {@inheritdoc}
     */
    public function isAvailable(): bool
    {
        // Check if the built-in CRM module is enabled
        $disabledModules = get_option('plover_crm_disabled_modules', []);

        // Native CRM is always available if the module is enabled
        // Don't check post_type_exists as it may not be registered yet during early initialization
        return !in_array('native_crm', $disabledModules);
    }

    /**
     * {@inheritdoc}
     */
    public function getName(): string
    {
        return 'Built-in CRM';
    }

    /**
     * {@inheritdoc}
     */
    public function getContact(int $id): ?array
    {
        if (!$this->isAvailable()) {
            return null;
        }

        $post = get_post($id);

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

        return $this->normalizeContact($post);
    }

    /**
     * {@inheritdoc}
     */
    public function getContactByEmail(string $email): ?array
    {
        if (!$this->isAvailable()) {
            return null;
        }

        $args = [
            'post_type' => 'plover_crm_contact',
            'posts_per_page' => 1,
            'meta_query' => [
                [
                    'key' => 'plover_crm_email',
                    'value' => $email,
                    'compare' => '='
                ]
            ]
        ];

        $query = new \WP_Query($args);

        if ($query->have_posts()) {
            return $this->normalizeContact($query->posts[0]);
        }

        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function createOrUpdateContact(array $data): ?array
    {
        if (!$this->isAvailable()) {
            return null;
        }

        $is_update = isset($data['id']) && !empty($data['id']);
        $contact_id = null;
        $is_new = false;

        // Handle full_name splitting if provided
        if (!empty($data['full_name']) && is_string($data['full_name'])) {
            $full_name = trim($data['full_name']);
            $name_parts = explode(' ', $full_name, 2);

            $data['first_name'] = $name_parts[0];
            $data['last_name'] = isset($name_parts[1]) ? $name_parts[1] : '';

            unset($data['full_name']);
        }

        // If ID is provided, this is an update
        if ($is_update) {
            $contact_id = intval($data['id']);
            $existing = $this->getContact($contact_id);

            if (!$existing) {
                $this->getLogger()->logError('Cannot update contact - contact not found', [
                    'contact_id' => $contact_id
                ]);
                return null;
            }

            $is_new = false;
        } else {
            // Creating new contact - validate unique field
            $unique_field = get_option('plover_crm_unique_field', 'email');

            // Validate unique field is provided
            $unique_value = null;

            if ($unique_field === 'email') {
                $unique_value = $data['email'] ?? '';
            } elseif ($unique_field === 'phone') {
                $unique_value = $data['phone'] ?? '';
            } elseif (strpos($unique_field, 'plover_crm_cf_') === 0) {
                // Custom field
                $cf_slug = str_replace('plover_crm_cf_', '', $unique_field);
                $unique_value = $data['custom_fields'][$cf_slug] ?? '';
            }

            if (empty($unique_value)) {
                $this->getLogger()->logError('Cannot create contact - unique field is required but not provided', [
                    'unique_field' => $unique_field
                ]);
                return null;
            }

            // If unique field is NOT email and email ends with @wpr.com, remove it
            if ($unique_field !== 'email' && !empty($data['email']) && str_ends_with($data['email'], '@wpr.com')) {
                unset($data['email']);
            }

            // Check if contact exists by unique field
            $existing = null;

            if ($unique_field === 'email') {
                $existing = $this->getContactByEmail($unique_value);
            } elseif ($unique_field === 'phone') {
                // Check by phone
                $args = [
                    'post_type' => 'plover_crm_contact',
                    'posts_per_page' => 1,
                    'meta_query' => [
                        [
                            'key' => 'plover_crm_phone',
                            'value' => $unique_value,
                            'compare' => '='
                        ]
                    ]
                ];
                $query = new \WP_Query($args);
                if ($query->have_posts()) {
                    $existing = $this->normalizeContact($query->posts[0]);
                }
            } else {
                // Check by custom field
                $cf_slug = str_replace('plover_crm_cf_', '', $unique_field);
                $args = [
                    'post_type' => 'plover_crm_contact',
                    'posts_per_page' => 1,
                    'meta_query' => [
                        [
                            'key' => 'plover_crm_cf_' . $cf_slug,
                            'value' => $unique_value,
                            'compare' => '='
                        ]
                    ]
                ];
                $query = new \WP_Query($args);
                if ($query->have_posts()) {
                    $existing = $this->normalizeContact($query->posts[0]);
                }
            }

            if ($existing) {
                // Update existing contact
                $contact_id = $existing['id'];
                $is_new = false;
            } else {
                // Create new contact
                $email = $data['email'] ?? '';
                $post_title = !empty($email) ? $email : $unique_value;

                $contact_id = wp_insert_post([
                    'post_type' => 'plover_crm_contact',
                    'post_title' => $post_title,
                    'post_status' => 'publish',
                ]);

                if (is_wp_error($contact_id)) {
                    return null;
                }

                $is_new = true;
            }
        }

        $previousStage = !$is_new && !empty($existing)
            ? $this->extractStageValue($existing)
            : null;

        // Save standard fields
        foreach (self::STANDARD_FIELDS as $key => $meta_key) {
            if (isset($data[$key])) {
                update_post_meta($contact_id, $meta_key, sanitize_text_field($data[$key]));
            }
        }

        // Generate hash
        if (isset($data['email'])) {
            update_post_meta($contact_id, 'plover_crm_hash', md5($data['email']));
        }

        // Handle lists
        if (isset($data['lists']) && is_array($data['lists'])) {
            wp_set_object_terms($contact_id, $data['lists'], 'plover_crm_list');
        }

        // Handle tags
        if (isset($data['tags']) && is_array($data['tags'])) {

            $tagResult = wp_set_object_terms($contact_id, $data['tags'], 'plover_crm_tag');

            if (is_wp_error($tagResult)) {

                $this->getLogger()->logError('Failed to set tags', [
                    'contact_id' => $contact_id,
                    'tags' => $data['tags'],
                    'error' => $tagResult->get_error_message()
                ]);
            }
        }

        // Handle custom fields with validation
        if (isset($data['custom_fields']) && is_array($data['custom_fields'])) {
            $this->saveValidatedCustomFields($contact_id, $data['custom_fields']);
        }
        $result = $this->getContact($contact_id);

        if ($result) {
            $result['is_new'] = $is_new;
            $currentStage = $this->extractStageValue($result);

            // Fire contact created hook after all meta is saved (skip during bulk import)
            if ($is_new && !\PloverCRM\Common\Utils::isBulkImporting()) {
                do_action('plover_crm/contact_created', $contact_id, $result);
            } elseif (!$is_new && !\PloverCRM\Common\Utils::isBulkImporting()) {
                $previousValues = [];
                $updatedValues = [];

                if ($previousStage !== $currentStage) {
                    $previousValues['stage-plover-crm'] = $previousStage;
                    $updatedValues['stage-plover-crm'] = $currentStage;
                }

                do_action('plover_crm/contact_updated', $contact_id, $result, $previousValues, $updatedValues);

                if (in_array($data['source'] ?? '', ['Form', 'Webhook'], true)) {
                    do_action('plover_crm/contact_touched', $contact_id, $result, $data);
                }
            }
        }

        return $result;
    }

    /**
     * {@inheritdoc}
     */
    public function getContactCustomFields(array $contact): array
    {
        // Custom fields are already included in the normalized contact data
        return $contact['custom_fields'] ?? [];
    }

    /**
     * {@inheritdoc}
     */
    public function getAllCustomFields(): array
    {
        if (!$this->isAvailable()) {
            return [];
        }

        return $this->customFieldsManager->getAllFields();
    }

    /**
     * {@inheritdoc}
     */
    public function createOrUpdateCustomFields(array $fields): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        foreach ($fields as $field) {
            // Normalize field for Native CRM
            $normalizedField = $this->normalizeCustomField($field);

            $slug = $normalizedField['slug'] ?? '';

            if (empty($slug)) {
                continue;
            }

            // Check if field exists
            $existingFields = $this->customFieldsManager->getAllFields();
            $exists = false;

            foreach ($existingFields as $existingField) {
                if ($existingField['slug'] === $slug) {
                    $exists = true;
                    break;
                }
            }

            if ($exists) {
                // Update existing field
                $this->customFieldsManager->updateField($slug, $normalizedField);
            } else {
                // Add new field
                $this->customFieldsManager->addField($normalizedField);
            }
        }

        return true;
    }

    /**
     * Normalize custom field structure for Native CRM
     * 
     * @param array $field Common field structure
     * @return array Native CRM-specific field structure
     */
    private function normalizeCustomField(array $field): array
    {
        // Map common types to Native CRM types
        $typeMap = [
            'datetime' => 'date_time',
            // Add more mappings as needed
        ];

        $type = $field['type'] ?? 'text';
        $mappedType = $typeMap[$type] ?? $type;

        // Native CRM structure
        $normalized = [
            'type' => $mappedType,
            'label' => $field['label'] ?? '',
            'slug' => $field['slug'] ?? '',
        ];

        // Add optional fields if present
        if (isset($field['group'])) {
            $normalized['group'] = $field['group'];
        }

        if (isset($field['options'])) {
            $normalized['options'] = $field['options'];
        }

        if (isset($field['readonly'])) {
            $normalized['readonly'] = $field['readonly'];
        }

        if (array_key_exists('system', $field)) {
            $normalized['system'] = (bool) $field['system'];
        }

        if (isset($field['owner_capability'])) {
            $normalized['owner_capability'] = (string) $field['owner_capability'];
        }

        if (isset($field['visibility'])) {
            $normalized['visibility'] = (string) $field['visibility'];
        }

        // Remove FluentCRM-specific fields if present
        unset($normalized['field_key']);

        return $normalized;
    }

    /**
     * {@inheritdoc}
     */
    public function getCustomFieldOptions(string $slug): array
    {
        if (!$this->isAvailable()) {
            return [];
        }

        $fields = $this->customFieldsManager->getAllFields();

        foreach ($fields as $field) {
            if ($field['slug'] === $slug) {
                return $field['options'] ?? [];
            }
        }

        return [];
    }

    /**
     * {@inheritdoc}
     */
    public function getAllLists(): array
    {
        if (!$this->isAvailable()) {
            return [];
        }

        $this->ensureTaxonomyRegistered('plover_crm_list');

        $terms = get_terms([
            'taxonomy' => 'plover_crm_list',
            'hide_empty' => false,
        ]);

        if (is_wp_error($terms)) {
            return [];
        }

        return array_map(function ($term) {
            return [
                'id' => $term->term_id,
                'title' => $term->name,
                'slug' => $term->slug,
            ];
        }, $terms);
    }

    /**
     * {@inheritdoc}
     */
    public function createList(array $data): ?array
    {
        if (!$this->isAvailable()) {
            return null;
        }

        $title = sanitize_text_field($data['title'] ?? '');
        $slug = !empty($data['slug']) ? sanitize_title($data['slug']) : sanitize_title($title);
        $description = sanitize_textarea_field($data['description'] ?? '');

        $result = wp_insert_term($title, 'plover_crm_list', [
            'slug' => $slug,
            'description' => $description,
        ]);

        if (is_wp_error($result)) {
            $this->getLogger()->logError('Failed to create list', [
                'error' => $result->get_error_message()
            ]);
            return null;
        }

        return [
            'id' => $result['term_id'],
            'title' => $title,
            'slug' => $slug,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function deleteList(int $id): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        $result = wp_delete_term($id, 'plover_crm_list');

        if (is_wp_error($result)) {
            $this->getLogger()->logError('Failed to delete list', [
                'list_id' => $id,
                'error' => $result->get_error_message()
            ]);
            return false;
        }

        return $result !== false;
    }

    /**
     * {@inheritdoc}
     */
    public function updateList(int $id, array $data): ?array
    {
        if (!$this->isAvailable()) {
            return null;
        }

        $term = get_term($id, 'plover_crm_list');
        if (!$term || is_wp_error($term)) {
            $this->getLogger()->logError('List not found for update', ['list_id' => $id]);
            return null;
        }

        $updateData = [];

        if (isset($data['title'])) {
            $updateData['name'] = sanitize_text_field($data['title']);
        }

        if (isset($data['slug'])) {
            $updateData['slug'] = sanitize_title($data['slug']);
        }

        if (isset($data['description'])) {
            $updateData['description'] = sanitize_textarea_field($data['description']);
        }

        if (empty($updateData)) {
            return [
                'id' => $term->term_id,
                'title' => $term->name,
                'slug' => $term->slug,
            ];
        }

        $result = wp_update_term($id, 'plover_crm_list', $updateData);

        if (is_wp_error($result)) {
            $this->getLogger()->logError('Failed to update list', [
                'list_id' => $id,
                'error' => $result->get_error_message()
            ]);
            return null;
        }

        $updatedTerm = get_term($result['term_id'], 'plover_crm_list');

        return [
            'id' => $updatedTerm->term_id,
            'title' => $updatedTerm->name,
            'slug' => $updatedTerm->slug,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function getContactLists(array $contact): array
    {
        // Lists are already included in the normalized contact data
        return $contact['lists'] ?? [];
    }

    /**
     * {@inheritdoc}
     */
    public function getContactTags(array $contact): array
    {
        // Tags are already included in the normalized contact data
        return $contact['tags'] ?? [];
    }

    /**
     * {@inheritdoc}
     */
    public function getOption(string $key, $default = null)
    {
        if (!$this->isAvailable()) {
            return $default;
        }

        return get_option('plover_crm_' . $key, $default);
    }

    /**
     * {@inheritdoc}
     */
    public function updateOption(string $key, $value): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        return update_option('plover_crm_' . $key, $value);
    }

    /**
     * {@inheritdoc}
     */
    public function getStandardFields(): array
    {
        return self::STANDARD_FIELD_LABELS;
    }

    /**
     * {@inheritdoc}
     */
    public function sanitizeContactData(array $data): array
    {
        $sanitized = [];

        if (isset($data['id'])) {
            $sanitized['id'] = intval($data['id']);
        }

        if (isset($data['email'])) {
            $sanitized['email'] = sanitize_email($data['email']);
        }

        $textFields = ['first_name', 'last_name', 'phone', 'city', 'state', 'country', 'postal_code'];

        foreach ($textFields as $field) {
            if (isset($data[$field])) {
                $sanitized[$field] = sanitize_text_field($data[$field]);
            }
        }

        if (isset($data['lists']) && is_array($data['lists'])) {
            $sanitized['lists'] = array_map('sanitize_text_field', $data['lists']);
        }

        if (isset($data['tags']) && is_array($data['tags'])) {
            $sanitized['tags'] = array_map('sanitize_text_field', $data['tags']);
        }

        if (isset($data['custom_fields']) && is_array($data['custom_fields'])) {
            $sanitized['custom_fields'] = $data['custom_fields'];
        }

        return $sanitized;
    }

    /**
     * {@inheritdoc}
     */
    public function registerHooks(): void
    {
        if (!$this->isAvailable()) {
            return;
        }

        // Hooks are already fired in NativeCRMModule::saveContactMeta
        // plover_crm/contact_created and plover_crm/contact_updated
    }

    /**
     * {@inheritdoc}
     */
    public function getAllTags(): array
    {
        if (!$this->isAvailable()) {
            return [];
        }

        $this->ensureTaxonomyRegistered('plover_crm_tag');

        $terms = get_terms([
            'taxonomy' => 'plover_crm_tag',
            'hide_empty' => false,
        ]);

        if (is_wp_error($terms)) {
            return [];
        }

        return array_map(function ($term) {
            return [
                'id' => $term->term_id,
                'title' => $term->name,
                'slug' => $term->slug,
            ];
        }, $terms);
    }

    /**
     * {@inheritdoc}
     */
    public function createTag(array $data): ?array
    {
        if (!$this->isAvailable()) {
            return null;
        }

        $title = sanitize_text_field($data['title'] ?? '');
        $slug = !empty($data['slug']) ? sanitize_title($data['slug']) : sanitize_title($title);
        $description = sanitize_textarea_field($data['description'] ?? '');

        $this->ensureTaxonomyRegistered('plover_crm_tag');

        $result = wp_insert_term($title, 'plover_crm_tag', [
            'slug' => $slug,
            'description' => $description,
        ]);

        if (is_wp_error($result)) {
            // Handle existing term
            if ($result->get_error_code() === 'term_exists') {
                $term_id = $result->get_error_data();
                return [
                    'id' => (int)$term_id,
                    'title' => $title,
                    'slug' => $slug,
                ];
            }

            $this->getLogger()->logError('Failed to create tag', [
                'error' => $result->get_error_message()
            ]);
            return null;
        }

        return [
            'id' => $result['term_id'],
            'title' => $title,
            'slug' => $slug,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function deleteTag(int $id): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        $result = wp_delete_term($id, 'plover_crm_tag');

        if (is_wp_error($result)) {
            $this->getLogger()->logError('Failed to delete tag', [
                'tag_id' => $id,
                'error' => $result->get_error_message()
            ]);
            return false;
        }

        return $result !== false;
    }

    /**
     * {@inheritdoc}
     */
    public function updateTag(int $id, array $data): ?array
    {
        if (!$this->isAvailable()) {
            return null;
        }

        $term = get_term($id, 'plover_crm_tag');
        if (!$term || is_wp_error($term)) {
            $this->getLogger()->logError('Tag not found for update', ['tag_id' => $id]);
            return null;
        }

        $updateData = [];

        if (isset($data['title'])) {
            $updateData['name'] = sanitize_text_field($data['title']);
        }

        if (isset($data['slug'])) {
            $updateData['slug'] = sanitize_title($data['slug']);
        }

        if (isset($data['description'])) {
            $updateData['description'] = sanitize_textarea_field($data['description']);
        }

        if (empty($updateData)) {
            return [
                'id' => $term->term_id,
                'title' => $term->name,
                'slug' => $term->slug,
            ];
        }

        $result = wp_update_term($id, 'plover_crm_tag', $updateData);

        if (is_wp_error($result)) {
            $this->getLogger()->logError('Failed to update tag', [
                'tag_id' => $id,
                'error' => $result->get_error_message()
            ]);
            return null;
        }

        $updatedTerm = get_term($result['term_id'], 'plover_crm_tag');

        return [
            'id' => $updatedTerm->term_id,
            'title' => $updatedTerm->name,
            'slug' => $updatedTerm->slug,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function getAllContacts(array $args = []): array
    {
        if (!$this->isAvailable()) {
            return ['contacts' => [], 'total' => 0];
        }

        $page = $args['page'] ?? 1;
        $per_page = $args['per_page'] ?? 20;
        $search = $args['search'] ?? '';

        $query_args = [
            'post_type' => 'plover_crm_contact',
            'posts_per_page' => $per_page,
            'paged' => $page,
            'post_status' => 'publish',
        ];

        if (!empty($search)) {
            $query_args['s'] = $search;
        }

        $query = new \WP_Query($query_args);

        $contacts = [];
        foreach ($query->posts as $post) {
            $contacts[] = $this->normalizeContact($post);
        }

        return [
            'contacts' => $contacts,
            'total' => $query->found_posts,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function searchContacts(array $args = []): array
    {
        if (!$this->isAvailable()) {
            return ['contacts' => [], 'total' => 0, 'total_pages' => 0];
        }

        $query = $args['query'] ?? '';
        $page = $args['page'] ?? 1;
        $per_page = $args['per_page'] ?? 20;
        $list_ids = $args['list_ids'] ?? [];
        $tag_ids = $args['tag_ids'] ?? [];
        $fields = $args['fields'] ?? [];
        $custom_fields = $args['custom_fields'] ?? [];
        $search_mode = $args['search_mode'] ?? 'or';
        $statuses = $args['statuses'] ?? [];
        $stages = $args['stages'] ?? [];

        $query_args = [
            'post_type' => 'plover_crm_contact',
            'post_status' => 'publish',
            'posts_per_page' => $per_page,
            'paged' => $page,
        ];

        // Apply list filter
        if (!empty($list_ids)) {
            $query_args['tax_query'][] = [
                'taxonomy' => 'plover_crm_list',
                'field' => 'term_id',
                'terms' => $list_ids,
                'operator' => 'IN',
            ];
        }

        // Apply tag filter
        if (!empty($tag_ids)) {
            $query_args['tax_query'][] = [
                'taxonomy' => 'plover_crm_tag',
                'field' => 'term_id',
                'terms' => $tag_ids,
                'operator' => 'IN',
            ];
        }

        // Handle tax_query relation
        if (!empty($query_args['tax_query']) && count($query_args['tax_query']) > 1) {
            $query_args['tax_query']['relation'] = 'AND';
        }

        // Apply stage filter (custom field exact match)
        if (!empty($stages)) {
            // Get the first (default) stage name from custom field options
            $defaultStage = '';
            $allCustomFields = $this->customFieldsManager->getAllFields();
            foreach ($allCustomFields as $cf) {
                if (isset($cf['slug']) && $cf['slug'] === 'stage-plover-crm') {
                    if (!empty($cf['options']) && is_array($cf['options'])) {
                        $defaultStage = $cf['options'][0] ?? '';
                    }
                    break;
                }
            }

            $includesDefault = $defaultStage && in_array($defaultStage, $stages);

            if ($includesDefault) {
                // Include contacts with matching stage OR no stage assigned
                $stage_meta = [
                    'relation' => 'OR',
                ];
                $stage_meta[] = [
                    'key' => 'plover_crm_cf_stage-plover-crm',
                    'value' => $stages,
                    'compare' => 'IN',
                ];
                $stage_meta[] = [
                    'key' => 'plover_crm_cf_stage-plover-crm',
                    'compare' => 'NOT EXISTS',
                ];
            } else {
                $stage_meta = [
                    [
                        'key' => 'plover_crm_cf_stage-plover-crm',
                        'value' => $stages,
                        'compare' => 'IN',
                    ],
                ];
            }

            if (!empty($query_args['meta_query'])) {
                $query_args['meta_query'] = [
                    'relation' => 'AND',
                    $query_args['meta_query'],
                    $stage_meta,
                ];
            } else {
                $query_args['meta_query'] = $stage_meta;
            }
        }

        // Apply text search
        if (!empty($query)) {
            $is_or_mode = ($search_mode === 'or');

            $meta_query = [];

            if (empty($fields) && empty($custom_fields)) {
                // Search ALL fields (standard + custom)
                foreach (self::STANDARD_FIELDS as $meta_key) {
                    $meta_query[] = [
                        'key' => $meta_key,
                        'value' => $query,
                        'compare' => 'LIKE',
                    ];
                }

                // All custom fields
                $all_custom_fields = $this->customFieldsManager->getAllFields();
                foreach ($all_custom_fields as $cf) {
                    $meta_query[] = [
                        'key' => 'plover_crm_cf_' . $cf['slug'],
                        'value' => $query,
                        'compare' => 'LIKE',
                    ];
                }

                $meta_query['relation'] = 'OR';
            } else {
                // Search specific fields only
                foreach ($fields as $field) {
                    if ($field === 'full_name') {
                        $meta_query[] = [
                            'key' => self::STANDARD_FIELDS['first_name'],
                            'value' => $query,
                            'compare' => 'LIKE',
                        ];
                        $meta_query[] = [
                            'key' => self::STANDARD_FIELDS['last_name'],
                            'value' => $query,
                            'compare' => 'LIKE',
                        ];
                    } elseif (isset(self::STANDARD_FIELDS[$field])) {
                        $meta_query[] = [
                            'key' => self::STANDARD_FIELDS[$field],
                            'value' => $query,
                            'compare' => 'LIKE',
                        ];
                    }
                }

                // Custom fields
                foreach ($custom_fields as $slug) {
                    $meta_query[] = [
                        'key' => 'plover_crm_cf_' . $slug,
                        'value' => $query,
                        'compare' => 'LIKE',
                    ];
                }

                $meta_query['relation'] = $is_or_mode ? 'OR' : 'AND';
            }

            if (!empty($meta_query)) {
                if (!empty($query_args['meta_query'])) {
                    // Combine with existing meta_query (e.g. stage filter) using AND
                    $query_args['meta_query'] = [
                        'relation' => 'AND',
                        $query_args['meta_query'],
                        $meta_query,
                    ];
                } else {
                    $query_args['meta_query'] = $meta_query;
                }
            }
        }

        $wp_query = new \WP_Query($query_args);

        $contacts = [];
        foreach ($wp_query->posts as $post) {
            $contacts[] = $this->normalizeContact($post);
        }

        return [
            'contacts' => $contacts,
            'total' => $wp_query->found_posts,
            'total_pages' => $wp_query->max_num_pages,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function deleteContact(int $id): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        $result = wp_delete_post($id, true);
        return !empty($result);
    }

    /**
     * {@inheritdoc}
     */
    public function getContactNotes(int $contact_id, array $args = []): array
    {
        if (!$this->isAvailable()) {
            return ['notes' => [], 'total' => 0];
        }

        $page = $args['page'] ?? 1;
        $per_page = $args['per_page'] ?? 20;

        $notesManager = new \PloverCRM\Modules\NativeCRM\NotesManager();
        return $notesManager->getContactNotes($contact_id, $page, $per_page);
    }

    /**
     * {@inheritdoc}
     */
    public function addContactNote(int $contact_id, array $data)
    {
        if (!$this->isAvailable()) {
            return false;
        }

        $notesManager = new \PloverCRM\Modules\NativeCRM\NotesManager();
        return $notesManager->addNote($contact_id, $data);
    }

    /**
     * {@inheritdoc}
     */
    public function updateNote(int $note_id, array $data): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        $notesManager = new \PloverCRM\Modules\NativeCRM\NotesManager();
        return $notesManager->updateNote($note_id, $data);
    }

    /**
     * {@inheritdoc}
     */
    public function deleteNote(int $note_id, array $data = []): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        $notesManager = new \PloverCRM\Modules\NativeCRM\NotesManager();
        return $notesManager->deleteNote($note_id, $data);
    }

    /**
     * Ensure taxonomy is registered (lazy load)
     * 
     * @param string $taxonomy Taxonomy slug
     */
    private function ensureTaxonomyRegistered(string $taxonomy): void
    {
        if (taxonomy_exists($taxonomy)) {
            return;
        }

        // Minimal registration for backend functionality
        register_taxonomy($taxonomy, 'plover_crm_contact', [
            'public' => false,
            'show_ui' => false,
            'hierarchical' => true,
            'rewrite' => false,
            'query_var' => true
        ]);
    }

    /**
     * Normalize contact post to array
     * 
     * @param \WP_Post $post
     * @return array
     */
    private function normalizeContact(\WP_Post $post): array
    {
        // Get standard fields using constants
        $data = [
            'id' => $post->ID,
        ];

        foreach (self::STANDARD_FIELDS as $key => $meta_key) {
            $data[$key] = get_post_meta($post->ID, $meta_key, true);
        }

        // Add computed fields
        $data['full_name'] = trim(($data['first_name'] ?? '') . ' ' . ($data['last_name'] ?? ''));
        $data['hash'] = get_post_meta($post->ID, 'plover_crm_hash', true);

        $data['created_at'] = $post->post_date;
        $data['updated_at'] = $post->post_modified;

        // Add avatar
        $data['plover_crm_avatar'] = $this->generateAvatar(
            $post->ID,
            $data['email'] ?? '',
            $data['first_name'] ?? '',
            $data['last_name'] ?? '',
            $data['hash'] ?? ''
        );

        // Add formatted custom fields
        $data['custom_fields'] = $this->formatCustomFields($post->ID);

        // Add last note
        $data['last_note'] = $this->getFormattedLastNote($post->ID);

        // Add tags
        $data['tags'] = $this->getContactTagsArray($post->ID);

        // Add lists
        $data['lists'] = $this->getContactListsArray($post->ID);

        return $data;
    }

    /**
     * Generate avatar URL
     */
    private function generateAvatar(int $contact_id, string $email, string $first_name, string $last_name, string $hash): string
    {
        // First, check if contact has a featured image (thumbnail)
        if (has_post_thumbnail($contact_id)) {
            $thumbnail_url = get_the_post_thumbnail_url($contact_id, 'thumbnail');
            if ($thumbnail_url) {
                return $thumbnail_url;
            }
        }

        // Fallback to Gravatar with UI Avatars
        $initials = ($first_name || $last_name)
            ? strtoupper(mb_substr($first_name, 0, 1) . mb_substr($last_name, 0, 1))
            : 'NA';

        // Use hash if available, otherwise generate from email
        if (empty($hash) && !empty($email)) {
            $hash = md5(strtolower(trim($email)));
        }

        return sprintf(
            'https://www.gravatar.com/avatar/%s?d=%s',
            $hash,
            urlencode("https://ui-avatars.com/api/{$initials}/128/random/fff")
        );
    }

    /**
     * Format custom fields
     */
    private function formatCustomFields(int $contact_id): array
    {
        $customFieldsManager = new CustomFieldsManager();
        $fields = $customFieldsManager->getAllFields();
        $formatted_fields = [];

        foreach ($fields as $field) {
            $value = get_post_meta($contact_id, 'plover_crm_cf_' . $field['slug'], true);

            if ($value !== '' && $value !== null) {
                $formatted_fields[] = [
                    'label' => $field['label'],
                    'key' => $field['slug'],
                    'value' => $value,
                ];
            }
        }

        return $formatted_fields;
    }

    /**
     * Get formatted last note
     */
    private function getFormattedLastNote(int $contact_id)
    {
        $notes = get_comments([
            'post_id' => $contact_id,
            'type' => 'plover_crm_note',
            'status' => 'approve',
            'number' => 1,
            'orderby' => 'comment_date',
            'order' => 'DESC',
        ]);

        if (empty($notes)) {
            return null;
        }

        $note = $notes[0];
        $created_by_id = (int) get_comment_meta($note->comment_ID, 'plover_crm_created_by_user_id', true);

        if (!$created_by_id && $note->user_id) {
            $created_by_id = (int) (CrmUserManager::getPublicIdByWordPressUserId((int) $note->user_id) ?: 0);
        }

        $created_by = [
            'id' => $created_by_id,
            'username' => 'Unknown'
        ];

        if ($created_by_id) {
            $crmUser = CrmUserManager::getPublicProfileById($created_by_id);
            if ($crmUser) {
                $created_by['username'] = $crmUser['username'];
            }
        }

        return (object) [
            'title' => get_comment_meta($note->comment_ID, 'plover_crm_note_title', true),
            'description' => $note->comment_content,
            'created_at' => $note->comment_date,
            'created_by' => $created_by,
        ];
    }

    /**
     * Get contact tags as array
     */
    private function getContactTagsArray(int $contact_id): array
    {
        $this->ensureTaxonomyRegistered('plover_crm_tag');
        $terms = wp_get_object_terms($contact_id, 'plover_crm_tag');

        if (is_wp_error($terms)) {
            return [];
        }

        return array_map(function ($term) {
            return [
                'id' => $term->term_id,
                'title' => $term->name,
                'slug' => $term->slug,
            ];
        }, $terms);
    }

    /**
     * Get contact lists as array
     */
    private function getContactListsArray(int $contact_id): array
    {
        $this->ensureTaxonomyRegistered('plover_crm_list');
        $terms = wp_get_object_terms($contact_id, 'plover_crm_list');

        if (is_wp_error($terms)) {
            return [];
        }

        return array_map(function ($term) {
            return [
                'id' => $term->term_id,
                'title' => $term->name,
                'slug' => $term->slug,
            ];
        }, $terms);
    }

    /**
     * Save custom fields with validation
     * 
     * @param int $contact_id
     * @param array $custom_fields
     */
    private function saveValidatedCustomFields(int $contact_id, array $custom_fields): void
    {
        // Get all custom field definitions
        $field_definitions = $this->customFieldsManager->getAllFields();
        $fields_by_slug = [];

        foreach ($field_definitions as $field) {
            $fields_by_slug[$field['slug']] = $field;
        }

        // Validate and save each custom field
        foreach ($custom_fields as $slug => $value) {
            // Skip if field definition doesn't exist
            if (!isset($fields_by_slug[$slug])) {
                $this->getLogger()->logWarning('Custom field does not exist, skipping', [
                    'field_slug' => $slug,
                    'contact_id' => $contact_id
                ]);
                continue;
            }

            $field = $fields_by_slug[$slug];
            $field_type = $field['type'] ?? 'text';

            // Validate value based on field type
            if (!$this->validateCustomFieldValue($value, $field)) {
                $this->getLogger()->logWarning('Invalid value for custom field, skipping', [
                    'field_slug' => $slug,
                    'field_type' => $field_type,
                    'contact_id' => $contact_id
                ]);
                continue;
            }

            // Normalize date/datetime values to standard format
            $value = $this->normalizeFieldValue($value, $field_type);

            // Save the validated value
            update_post_meta($contact_id, 'plover_crm_cf_' . $slug, $value);
        }
    }

    private function extractStageValue(array $contact): ?string
    {
        foreach ((array) ($contact['custom_fields'] ?? []) as $field) {
            if (!is_array($field) || ($field['key'] ?? '') !== 'stage-plover-crm') {
                continue;
            }

            $value = $field['value'] ?? null;
            if ($value === null || $value === '') {
                return null;
            }

            return (string) $value;
        }

        return null;
    }

    /**
     * Normalize field value to standard format
     * 
     * @param mixed $value
     * @param string $field_type
     * @return mixed
     */
    private function normalizeFieldValue($value, string $field_type)
    {
        if ($value === '' || $value === null) {
            return $value;
        }

        switch ($field_type) {
            case 'date':
                return DateTimeHelper::normalizeDate($value, 'Y-m-d');
            case 'date_time':
                return DateTimeHelper::normalizeDateTime($value, 'Y-m-d H:i');
            default:
                return $value;
        }
    }

    /**
     * Normalize date value to YYYY-MM-DD format
     * 
     * @param string $value
     * @return string
     */
    private function normalizeDateValue(string $value): string
    {
        // Try strtotime first (handles many formats like Y-m-d, m/d/Y, etc.)
        $timestamp = strtotime($value);
        if ($timestamp !== false) {
            return date('Y-m-d', $timestamp);
        }

        // Common date formats to try
        $formats = [
            'd/m/Y',        // 06/02/2026
            'd-m-Y',        // 06-02-2026
            'd.m.Y',        // 06.02.2026
            'M/d/Y',        // Feb/06/2026
            'M-d-Y',        // Feb-06-2026
            'M.d.Y',        // Feb.06.2026
            'F/d/Y',        // February/06/2026
            'F-d-Y',        // February-06-2026
            'F.d.Y',        // February.06.2026
            'd/M/Y',        // 06/Feb/2026
            'd-M-Y',        // 06-Feb-2026
            'd.M.Y',        // 06.Feb.2026
            'd/F/Y',        // 06/February/2026
            'd-F-Y',        // 06-February-2026
            'd.F.Y',        // 06.February.2026
            'Y/m/d',        // 2026/02/06
            'Y.m.d',        // 2026.02.06
            'd M Y',        // 06 Feb 2026
            'd F Y',        // 06 February 2026
            'M d, Y',       // Feb 06, 2026
            'F d, Y',       // February 06, 2026
        ];

        foreach ($formats as $format) {
            $parsed = \DateTime::createFromFormat($format, $value);
            if ($parsed !== false && $parsed->format($format) === $value) {
                return $parsed->format('Y-m-d');
            }
        }

        // Return original value if parsing fails
        return $value;
    }

    /**
     * Normalize datetime value to YYYY-MM-DD HH:MM format
     * 
     * @param string $value
     * @return string
     */
    private function normalizeDateTimeValue(string $value): string
    {
        // Try strtotime first (handles many formats)
        $timestamp = strtotime($value);
        if ($timestamp !== false) {
            return date('Y-m-d H:i', $timestamp);
        }

        // Common datetime formats to try
        $formats = [
            'd/m/Y h:i A',      // 06/02/2026 12:00 PM
            'd/m/Y H:i',        // 06/02/2026 12:00
            'd-m-Y h:i A',      // 06-02-2026 12:00 PM
            'd-m-Y H:i',        // 06-02-2026 12:00
            'd.m.Y h:i A',      // 06.02.2026 12:00 PM
            'd.m.Y H:i',        // 06.02.2026 12:00
            'm/d/Y h:i A',      // 02/06/2026 12:00 PM
            'm/d/Y H:i',        // 02/06/2026 12:00
            'm-d-Y h:i A',      // 02-06-2026 12:00 PM
            'm-d-Y H:i',        // 02-06-2026 12:00
            'Y/m/d H:i',        // 2026/02/06 12:00
            'Y-m-d H:i',        // 2026-02-06 12:00
            'Y.m.d H:i',        // 2026.02.06 12:00
            'd M Y h:i A',      // 06 Feb 2026 12:00 PM
            'd M Y H:i',        // 06 Feb 2026 12:00
            'd F Y h:i A',      // 06 February 2026 12:00 PM
            'd F Y H:i',        // 06 February 2026 12:00
            'M d, Y h:i A',     // Feb 06, 2026 12:00 PM
            'M d, Y H:i',       // Feb 06, 2026 12:00
            'F d, Y h:i A',     // February 06, 2026 12:00 PM
            'F d, Y H:i',       // February 06, 2026 12:00
        ];

        foreach ($formats as $format) {
            $parsed = \DateTime::createFromFormat($format, $value);
            if ($parsed !== false && $parsed->format($format) === $value) {
                return $parsed->format('Y-m-d H:i');
            }
        }

        // Return original value if parsing fails
        return $value;
    }

    /**
     * Validate custom field value against field type
     * 
     * @param mixed $value
     * @param array $field
     * @return bool
     */
    private function validateCustomFieldValue($value, array $field): bool
    {
        $field_type = $field['type'] ?? 'text';

        // Empty values are allowed for optional fields
        if ($value === '' || $value === null) {
            return true;
        }

        switch ($field_type) {
            case 'select':
            case 'radio':
                // Validate against available options
                $options = $field['options'] ?? [];
                if (empty($options)) {
                    return true; // No options defined, allow any value
                }
                return in_array($value, $options, true);

            case 'checkbox':
                // Checkbox can be boolean or array of values
                if (is_bool($value) || $value === '0' || $value === '1') {
                    return true;
                }
                if (is_array($value)) {
                    $options = $field['options'] ?? [];
                    if (empty($options)) {
                        return true;
                    }
                    // All values must be in options
                    foreach ($value as $v) {
                        if (!in_array($v, $options, true)) {
                            return false;
                        }
                    }
                    return true;
                }
                return false;

            case 'email':
                return is_email($value);

            case 'url':
                return filter_var($value, FILTER_VALIDATE_URL) !== false;

            case 'number':
                return is_numeric($value);

            case 'date':
                // Validate date format - accept various formats
                return DateTimeHelper::isValidDate($value);

            case 'date_time':
                // Validate datetime format - accept various formats
                return DateTimeHelper::isValidDateTime($value);

            case 'text':
            case 'textarea':
            default:
                // Text fields accept any string value
                return is_string($value) || is_numeric($value);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getActivityTypes(): array
    {
        $noteTypes = \PloverCRM\Modules\NativeCRM\NotesManager::getNoteTypes();
        $types = [];

        foreach ($noteTypes as $id => $label) {
            $types[] = \PloverCRM\Core\CRM\Schemas\ActivityTypeSchema::normalize([
                'id' => $id,
                'label' => $label,
            ]);
        }

        return $types;
    }

    /**
     * {@inheritdoc}
     */
    public function getRequiredUniqueField(): array
    {
        $uniqueField = get_option('plover_crm_unique_field', 'email');

        // Check if it's a custom field
        if (strpos($uniqueField, 'plover_crm_cf_') === 0) {
            $slug = str_replace('plover_crm_cf_', '', $uniqueField);
            $customFields = $this->getAllCustomFields();

            $label = ucfirst(str_replace(['_', '-'], ' ', $slug));
            foreach ($customFields as $cf) {
                if ($cf['slug'] === $slug) {
                    $label = $cf['label'];
                    break;
                }
            }

            return [
                'field' => $slug,
                'label' => $label,
                'is_custom_field' => true,
            ];
        }

        // Standard field
        return [
            'field' => $uniqueField,
            'label' => self::STANDARD_FIELD_LABELS[$uniqueField] ?? ucfirst($uniqueField),
            'is_custom_field' => false,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function validateContactData(array $data): array
    {
        $uniqueFieldInfo = $this->getRequiredUniqueField();
        $field = $uniqueFieldInfo['field'];
        $label = $uniqueFieldInfo['label'];
        $isCustomField = $uniqueFieldInfo['is_custom_field'];

        // Check if the required unique field is present
        if ($isCustomField) {
            $value = $data['custom_fields'][$field] ?? null;
        } else {
            $value = $data[$field] ?? null;
        }

        if (empty($value)) {
            return [
                'valid' => false,
                'error_code' => 'missing_' . $field,
                'error_message' => "{$label} is required as it is configured as the unique identifier",
            ];
        }

        // Additional validation for email
        if ($field === 'email' && !filter_var($value, FILTER_VALIDATE_EMAIL)) {
            return [
                'valid' => false,
                'error_code' => 'invalid_email',
                'error_message' => 'Please provide a valid email address',
            ];
        }

        return ['valid' => true, 'error_code' => null, 'error_message' => null];
    }

    /**
     * {@inheritdoc}
     */
    public function getContactOwner(int $contactId): ?int
    {
        if (!$this->isAvailable()) {
            return null;
        }

        $ownerId = get_post_meta($contactId, 'plover_crm_contact_owner', true);
        return $ownerId ? intval($ownerId) : null;
    }

    /**
     * {@inheritdoc}
     */
    public function setContactOwner(int $contactId, ?int $userId): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        // Verify contact exists
        $post = get_post($contactId);
        if (!$post || $post->post_type !== 'plover_crm_contact') {
            return false;
        }

        if ($userId === null) {
            delete_post_meta($contactId, 'plover_crm_contact_owner');
        } else {
            update_post_meta($contactId, 'plover_crm_contact_owner', $userId);
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function getContactsByOwner(array $args = []): array
    {
        if (!$this->isAvailable()) {
            return ['contacts' => [], 'total' => 0];
        }

        $page = $args['page'] ?? 1;
        $per_page = $args['per_page'] ?? 20;
        $search = $args['search'] ?? '';
        $owner_id = $args['owner_id'] ?? null;
        $include_unassigned = $args['include_unassigned'] ?? false;
        $only_unassigned = $args['only_unassigned'] ?? false;

        $query_args = [
            'post_type' => 'plover_crm_contact',
            'posts_per_page' => $per_page,
            'paged' => $page,
            'orderby' => 'ID',
            'order' => 'DESC',
        ];

        // Build meta query for ownership
        $meta_query = [];

        if ($only_unassigned) {
            $meta_query[] = [
                'relation' => 'OR',
                [
                    'key' => 'plover_crm_contact_owner',
                    'compare' => 'NOT EXISTS',
                ],
                [
                    'key' => 'plover_crm_contact_owner',
                    'value' => '',
                    'compare' => '=',
                ],
            ];
        } elseif ($owner_id !== null) {
            if ($include_unassigned) {
                $meta_query[] = [
                    'relation' => 'OR',
                    [
                        'key' => 'plover_crm_contact_owner',
                        'value' => $owner_id,
                        'compare' => '=',
                    ],
                    [
                        'key' => 'plover_crm_contact_owner',
                        'compare' => 'NOT EXISTS',
                    ],
                    [
                        'key' => 'plover_crm_contact_owner',
                        'value' => '',
                        'compare' => '=',
                    ],
                ];
            } else {
                $meta_query[] = [
                    'key' => 'plover_crm_contact_owner',
                    'value' => $owner_id,
                    'compare' => '=',
                ];
            }
        }

        if (!empty($meta_query)) {
            $query_args['meta_query'] = $meta_query;
        }

        // Apply search filter
        if (!empty($search)) {
            $query_args['s'] = $search;
        }

        $query = new \WP_Query($query_args);

        $contacts = [];
        foreach ($query->posts as $post) {
            $contacts[] = $this->normalizeContact($post);
        }

        return [
            'contacts' => $contacts,
            'total' => $query->found_posts,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function updateCustomFieldValue(string $fieldSlug, string $oldValue, string $newValue): int
    {
        if (!$this->isAvailable()) {
            return 0;
        }

        global $wpdb;
        $meta_key = 'plover_crm_cf_' . $fieldSlug;

        $updated = $wpdb->update(
            $wpdb->postmeta,
            ['meta_value' => $newValue],
            [
                'meta_key' => $meta_key,
                'meta_value' => $oldValue
            ],
            ['%s'],
            ['%s', '%s']
        );

        return $updated !== false ? $updated : 0;
    }

    /**
     * {@inheritdoc}
     */
    public function countContactsWithCustomFieldValue(string $fieldSlug, string $value): int
    {
        if (!$this->isAvailable()) {
            return 0;
        }

        global $wpdb;
        $meta_key = 'plover_crm_cf_' . $fieldSlug;

        // Only count contacts (plover_crm_contact post type)
        $count = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(DISTINCT pm.post_id) 
             FROM {$wpdb->postmeta} pm
             INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID
             WHERE pm.meta_key = %s 
             AND pm.meta_value = %s 
             AND p.post_type = 'plover_crm_contact'
             AND p.post_status = 'publish'",
            $meta_key,
            $value
        ));

        return (int) $count;
    }

    /**
     * {@inheritdoc}
     */
    public function countContactsWithoutCustomField(string $fieldSlug): int
    {
        if (!$this->isAvailable()) {
            return 0;
        }

        global $wpdb;
        $meta_key = 'plover_crm_cf_' . $fieldSlug;

        $count = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->posts} p
             WHERE p.post_type = 'plover_crm_contact'
             AND p.post_status = 'publish'
             AND NOT EXISTS (
                 SELECT 1 FROM {$wpdb->postmeta} pm
                 WHERE pm.post_id = p.ID
                 AND pm.meta_key = %s
             )",
            $meta_key
        ));

        return (int) $count;
    }

    /**
     * {@inheritdoc}
     */
    public function getAdminMenuParent(): string
    {
        return 'edit.php?post_type=plover_crm_contact';
    }
}
