<?php

namespace PloverCRM\Core\CRM;

use PloverCRM\Core\CRM\Schemas\ContactSchema;
use PloverCRM\Core\CRM\Schemas\ListSchema;
use PloverCRM\Core\CRM\Schemas\TagSchema;
use PloverCRM\Core\CRM\Schemas\NoteSchema;

/**
 * CRM Provider Validator
 * 
 * Validates that CRM providers implement required methods and return correct data formats
 */
class ProviderValidator
{
    /**
     * @var CRMProviderInterface
     */
    private $provider;

    /**
     * @var array Validation errors
     */
    private $errors = [];

    /**
     * Constructor
     * 
     * @param CRMProviderInterface $provider
     */
    public function __construct(CRMProviderInterface $provider)
    {
        $this->provider = $provider;
    }

    /**
     * Validate provider implementation
     * 
     * @return array ['valid' => bool, 'errors' => array]
     */
    public function validate(): array
    {
        $this->errors = [];

        // Check required methods exist
        $this->validateRequiredMethods();

        // If provider is available, validate data formats
        if ($this->provider->isAvailable()) {
            $this->validateDataFormats();
        }

        return [
            'valid' => empty($this->errors),
            'errors' => $this->errors,
            'provider' => $this->provider->getName(),
        ];
    }

    /**
     * Validate required methods are implemented
     */
    private function validateRequiredMethods(): void
    {
        $requiredMethods = [
            'isAvailable',
            'getName',
            'getContact',
            'getContactByEmail',
            'createOrUpdateContact',
            'getAllLists',
            'getAllTags',
            'getAllContacts',
            'deleteContact',
            'getContactNotes',
            'addContactNote',
            'updateNote',
            'deleteNote',
            'getAllCustomFields',
        ];

        foreach ($requiredMethods as $method) {
            if (!method_exists($this->provider, $method)) {
                $this->errors[] = "Provider must implement method: {$method}()";
            }
        }
    }

    /**
     * Validate data formats returned by provider
     */
    private function validateDataFormats(): void
    {
        // Only validate if provider has data
        try {
            // Validate lists format
            $lists = $this->provider->getAllLists();
            if (!empty($lists)) {
                $this->validateLists($lists);
            }

            // Validate tags format
            $tags = $this->provider->getAllTags();
            if (!empty($tags)) {
                $this->validateTags($tags);
            }

            // Validate contacts format (get first contact if any)
            $contacts = $this->provider->getAllContacts(['page' => 1, 'per_page' => 1]);
            if (!empty($contacts['contacts'])) {
                $this->validateContact($contacts['contacts'][0]);
            }
        } catch (\Exception $e) {
            $this->errors[] = "Error validating provider data: " . $e->getMessage();
        }
    }

    /**
     * Validate contact data format
     */
    private function validateContact(array $contact): void
    {
        $validation = ContactSchema::validate($contact);
        
        if (!$validation['valid']) {
            foreach ($validation['errors'] as $error) {
                $this->errors[] = "Contact schema error: {$error}";
            }
        }
    }

    /**
     * Validate lists data format
     */
    private function validateLists(array $lists): void
    {
        foreach ($lists as $index => $list) {
            $validation = ListSchema::validate($list);
            
            if (!$validation['valid']) {
                foreach ($validation['errors'] as $error) {
                    $this->errors[] = "List[{$index}] schema error: {$error}";
                }
            }
        }
    }

    /**
     * Validate tags data format
     */
    private function validateTags(array $tags): void
    {
        foreach ($tags as $index => $tag) {
            $validation = TagSchema::validate($tag);
            
            if (!$validation['valid']) {
                foreach ($validation['errors'] as $error) {
                    $this->errors[] = "Tag[{$index}] schema error: {$error}";
                }
            }
        }
    }

    /**
     * Get validation errors
     * 
     * @return array
     */
    public function getErrors(): array
    {
        return $this->errors;
    }

    /**
     * Check if provider is valid
     * 
     * @return bool
     */
    public function isValid(): bool
    {
        return empty($this->errors);
    }
}
