<?php

namespace PloverCRM\Core\CRM;

use PloverCRM\Core\CRM\Providers\FluentCRMProvider;
use PloverCRM\Core\CRM\Providers\NativeCRMProvider;
use PloverCRM\Core\Services\Logger;

/**
 * CRM Manager
 * 
 * Facade for interacting with CRM providers
 * Automatically detects and uses the available CRM provider
 */
class CRMManager implements CRMProviderInterface
{
    /**
     * @var CRMProviderInterface|null Active CRM provider
     */
    private $provider = null;

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

    /**
     * @var array Available providers mapped to module IDs
     */
    private $providerMap = [
        'fluent_crm' => FluentCRMProvider::class,
        'native_crm' => NativeCRMProvider::class,
        // 'mailpoet' => MailPoetProvider::class, // Future
    ];

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

    /**
     * @var array Default priority order (used when no selection is made)
     */
    private $defaultPriority = [
        'fluent_crm',
        'native_crm',
    ];

    /**
     * @var array Validation results for all providers
     */
    private $validationResults = [];

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->detectProvider();
        $this->validateProviders();
    }

    /**
     * Detect and initialize the active CRM provider
     * 
     * @return void
     */
    private function detectProvider(): void
    {
        // Get user's selected CRM provider
        $selectedProvider = get_option('plover_crm_selected_crm', '');

        // Get disabled modules
        $disabledModules = get_option('plover_crm_disabled_modules', []);

        // Try user's selection first
        if (!empty($selectedProvider) && isset($this->providerMap[$selectedProvider])) {
            // Check if the selected module is not disabled
            if (!in_array($selectedProvider, $disabledModules)) {
                $providerClass = $this->providerMap[$selectedProvider];
                $provider = new $providerClass();

                if ($provider->isAvailable()) {
                    $this->provider = $provider;
                    return;
                }
            }
        }

        // Fall back to priority order
        foreach ($this->defaultPriority as $moduleId) {
            // Skip if module is disabled
            if (in_array($moduleId, $disabledModules)) {
                continue;
            }

            if (isset($this->providerMap[$moduleId])) {
                $providerClass = $this->providerMap[$moduleId];
                $provider = new $providerClass();

                if ($provider->isAvailable()) {
                    $this->provider = $provider;
                    break;
                }
            }
        }

        if ($this->provider) {
            // Provider loaded successfully
        } else {
            $this->getLogger()->logError('No CRM provider available');
        }
    }

    /**
     * Get all available CRM providers
     * 
     * @return array Array of provider info [module_id => [name, available, class]]
     */
    public function getAvailableProviders(): array
    {
        $providers = [];
        $disabledModules = get_option('plover_crm_disabled_modules', []);

        foreach ($this->providerMap as $moduleId => $providerClass) {
            $provider = new $providerClass();
            $providers[$moduleId] = [
                'name' => $provider->getName(),
                'available' => $provider->isAvailable(),
                'enabled' => !in_array($moduleId, $disabledModules),
                'class' => $providerClass,
            ];
        }

        return $providers;
    }

    /**
     * Get the currently selected provider module ID
     * 
     * @return string
     */
    public function getSelectedProviderId(): string
    {
        if (!$this->provider) {
            return '';
        }

        // Find the module ID for the current provider
        $providerClass = get_class($this->provider);
        foreach ($this->providerMap as $moduleId => $class) {
            if ($class === $providerClass) {
                return $moduleId;
            }
        }

        return '';
    }

    /**
     * Get the active provider instance
     * 
     * @return CRMProviderInterface|null
     */
    public function getProvider(): ?CRMProviderInterface
    {
        return $this->provider;
    }

    /**
     * Resolve a specific provider by ID without changing the selected provider.
     */
    public function getProviderById(string $providerId): ?CRMProviderInterface
    {
        if ($providerId === '' || !isset($this->providerMap[$providerId])) {
            return null;
        }

        $disabledModules = get_option('plover_crm_disabled_modules', []);
        if (in_array($providerId, $disabledModules, true)) {
            return null;
        }

        $providerClass = $this->providerMap[$providerId];
        $provider = new $providerClass();

        return $provider->isAvailable() ? $provider : null;
    }

    /**
     * Validate all available providers
     * 
     * @return void
     */
    private function validateProviders(): void
    {
        foreach ($this->providerMap as $moduleId => $providerClass) {
            $provider = new $providerClass();

            // Only validate if provider is available
            if (!$provider->isAvailable()) {
                continue;
            }

            $validator = new ProviderValidator($provider);
            $result = $validator->validate();

            $this->validationResults[$moduleId] = $result;

            // Log errors if validation failed
            if (!$result['valid']) {
                $this->getLogger()->logError('Provider validation failed', [
                    'provider' => $provider->getName(),
                    'errors' => $result['errors']
                ]);
            }
        }
    }

    /**
     * Get validation results for all providers
     * 
     * @return array
     */
    public function getValidationResults(): array
    {
        return $this->validationResults;
    }

    /**
     * Get validation result for a specific provider
     * 
     * @param string $moduleId
     * @return array|null
     */
    public function getProviderValidation(string $moduleId): ?array
    {
        return $this->validationResults[$moduleId] ?? null;
    }

    /**
     * Check if current provider is valid
     * 
     * @return bool
     */
    public function isCurrentProviderValid(): bool
    {
        $providerId = $this->getSelectedProviderId();
        if (empty($providerId)) {
            return false;
        }

        $validation = $this->getProviderValidation($providerId);
        return $validation && $validation['valid'];
    }

    /**
     * {@inheritdoc}
     */
    public function isAvailable(): bool
    {
        return $this->provider !== null && $this->provider->isAvailable();
    }

    /**
     * {@inheritdoc}
     */
    public function getName(): string
    {
        return $this->provider ? $this->provider->getName() : 'None';
    }

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

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

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

    /**
     * {@inheritdoc}
     */
    public function getContactCustomFields(array $contact): array
    {
        return $this->provider ? $this->provider->getContactCustomFields($contact) : [];
    }

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

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

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

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

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

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

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

    /**
     * {@inheritdoc}
     */
    public function getContactLists(array $contact): array
    {
        return $this->provider ? $this->provider->getContactLists($contact) : [];
    }

    /**
     * {@inheritdoc}
     */
    public function getContactTags(array $contact): array
    {
        return $this->provider ? $this->provider->getContactTags($contact) : [];
    }

    /**
     * {@inheritdoc}
     */
    public function getOption(string $key, $default = null)
    {
        return $this->provider ? $this->provider->getOption($key, $default) : $default;
    }

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

    /**
     * {@inheritdoc}
     */
    public function getStandardFields(): array
    {
        return $this->provider ? $this->provider->getStandardFields() : [];
    }

    /**
     * {@inheritdoc}
     */
    public function sanitizeContactData(array $data): array
    {
        return $this->provider ? $this->provider->sanitizeContactData($data) : $data;
    }

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

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

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

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

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

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

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

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

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

    /**
     * {@inheritdoc}
     */
    public function addContactNote(int $contact_id, array $data)
    {
        return $this->provider ? $this->provider->addContactNote($contact_id, $data) : false;
    }

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

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

    /**
     * {@inheritdoc}
     */
    public function getActivityTypes(): array
    {
        return $this->provider ? $this->provider->getActivityTypes() : [];
    }

    /**
     * {@inheritdoc}
     */
    public function getRequiredUniqueField(): array
    {
        return $this->provider ? $this->provider->getRequiredUniqueField() : [
            'field' => 'email',
            'label' => 'Email',
            'is_custom_field' => false,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function validateContactData(array $data): array
    {
        return $this->provider ? $this->provider->validateContactData($data) : [
            'valid' => false,
            'error_code' => 'no_provider',
            'error_message' => 'No CRM provider available',
        ];
    }

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

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

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

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

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

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

    /**
     * {@inheritdoc}
     */
    public function getAdminMenuParent(): string
    {
        return $this->provider ? $this->provider->getAdminMenuParent() : 'options-general.php';
    }
}
