<?php

namespace App\Services;

use App\Models\Committee;
use App\Models\WorkGroup;
use App\Services\HubSpot\HubSpotApiClient;
use App\Services\HubSpot\HubSpotListService;
use App\Services\HubSpot\HubSpotContactService;
use App\Services\HubSpot\HubSpotSyncOrchestrator;
use App\Services\HubSpot\HubSpotSyncMetrics;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;

/**
 * HubSpot Sync Service
 *
 * Main facade for HubSpot synchronization operations.
 * Provides a simple interface for common operations and
 * developer utility methods.
 */
class HubSpotSyncService
{
    /**
     * @var HubSpotApiClient
     */
    protected $apiClient;

    /**
     * @var HubSpotSyncOrchestrator
     */
    protected $orchestrator;

    /**
     * @var HubSpotListService
     */
    protected $listService;

    /**
     * @var HubSpotContactService
     */
    protected $contactService;

    /**
     * Create a new HubSpotSyncService instance.
     */
    public function __construct()
    {
        $this->apiClient = new HubSpotApiClient();
        $this->orchestrator = new HubSpotSyncOrchestrator($this->apiClient);
        $this->listService = $this->orchestrator->getListService();
        $this->contactService = $this->orchestrator->getContactService();
    }

    /**
     * Check if HubSpot sync is available.
     *
     * @return bool
     */
    public static function isAvailable(): bool
    {
        return HubSpotApiClient::isAvailable();
    }

    /**
     * Initialize the service (connects to HubSpot API).
     *
     * @return self
     */
    public function initialize(): self
    {
        $this->apiClient->initialize();
        return $this;
    }

    /**
     * Test the HubSpot API connection.
     *
     * @return array
     */
    public function testConnection(): array
    {
        return $this->apiClient->testConnection();
    }

    /**
     * Set dry-run mode for all operations.
     *
     * @param bool $dryRun
     * @return self
     */
    public function setDryRun(bool $dryRun): self
    {
        $this->apiClient->setDryRun($dryRun);
        return $this;
    }

    // =========================================================================
    // SYNC OPERATIONS
    // =========================================================================

    /**
     * Run the full synchronization process.
     *
     * This will:
     * 1. Get all committees and workgroups with active users
     * 2. Compare with existing HubSpot lists (matching suffix pattern)
     * 3. Create new lists for new committees/workgroups
     * 4. Delete lists for removed committees/workgroups
     * 5. Sync contacts in each list (add missing, remove extra)
     *
     * @param bool $dryRun If true, no actual changes will be made
     * @return HubSpotSyncMetrics
     */
    /**
     * Run the full synchronization process, with optional filtering by type.
     *
     * @param bool $dryRun
     * @param string|null $type 'committee', 'workgroup', or null for both
     * @return HubSpotSyncMetrics
     */
    public function syncAll(bool $dryRun = false, ?string $type = null): HubSpotSyncMetrics
    {
        return $this->orchestrator->syncAll($dryRun, $type);
    }

    // =========================================================================
    // LIST OPERATIONS (Developer Utilities)
    // =========================================================================

    /**
     * Get all server-sync lists from HubSpot.
     *
     * @return array
     */
    public function getAllLists(): array
    {
        $this->initialize();
        return $this->listService->getAllServerSyncLists();
    }

    /**
     * Get a HubSpot list by its title.
     *
     * @param string $title The committee/workgroup list title
     * @return array|null
     */
    public function getListByTitle(string $title): ?array
    {
        $this->initialize();
        return $this->listService->getListByTitle($title);
    }

    /**
     * Get the HubSpot list for a specific committee.
     *
     * @param Committee $committee
     * @return array|null
     */
    public function getListByCommittee(Committee $committee): ?array
    {
        $title = $this->getCommitteeTitle($committee);
        if (empty($title)) {
            return null;
        }
        return $this->getListByTitle("Committee: {$title}");
    }

    /**
     * Get the HubSpot list for a specific workgroup.
     *
     * @param WorkGroup $workGroup
     * @return array|null
     */
    public function getListByWorkGroup(WorkGroup $workGroup): ?array
    {
        $title = $this->getWorkGroupTitle($workGroup);
        if (empty($title)) {
            return null;
        }
        return $this->getListByTitle("WorkGroup: {$title}");
    }

    /**
     * Create a HubSpot list for a committee.
     *
     * @param Committee $committee
     * @return array|null
     */
    public function createListForCommittee(Committee $committee): ?array
    {
        $this->initialize();
        $title = $this->getCommitteeTitle($committee);
        if (empty($title)) {
            return null;
        }
        return $this->listService->createList("Committee: {$title}");
    }

    /**
     * Create a HubSpot list for a workgroup.
     *
     * @param WorkGroup $workGroup
     * @return array|null
     */
    public function createListForWorkGroup(WorkGroup $workGroup): ?array
    {
        $this->initialize();
        $title = $this->getWorkGroupTitle($workGroup);
        if (empty($title)) {
            return null;
        }
        return $this->listService->createList("WorkGroup: {$title}");
    }

    /**
     * Delete a HubSpot list by title.
     *
     * @param string $title
     * @return bool
     */
    public function deleteListByTitle(string $title): bool
    {
        $this->initialize();
        return $this->listService->deleteListByTitle($title);
    }

    // =========================================================================
    // CONTACT OPERATIONS (Developer Utilities)
    // =========================================================================

    /**
     * Add a contact to a list by list title.
     *
     * @param string $listTitle The list title (e.g., "Committee: Finance")
     * @param string $email
     * @return bool
     */
    public function addContactToList(string $listTitle, string $email): bool
    {
        $this->initialize();
        $list = $this->listService->getListByTitle($listTitle);

        if ($list === null) {
            return false;
        }

        return $this->contactService->addContactToList($list['listId'], $email);
    }

    /**
     * Remove a contact from a list by list title.
     *
     * @param string $listTitle The list title (e.g., "Committee: Finance")
     * @param string $email
     * @return bool
     */
    public function removeContactFromList(string $listTitle, string $email): bool
    {
        $this->initialize();
        $list = $this->listService->getListByTitle($listTitle);

        if ($list === null) {
            return false;
        }

        return $this->contactService->removeContactFromList($list['listId'], $email);
    }

    /**
     * Add a contact to a committee's list.
     *
     * @param Committee $committee
     * @param string $email
     * @return bool
     */
    public function addContactToCommittee(Committee $committee, string $email): bool
    {
        $title = $this->getCommitteeTitle($committee);
        if (empty($title)) {
            return false;
        }
        return $this->addContactToList("Committee: {$title}", $email);
    }

    /**
     * Remove a contact from a committee's list.
     *
     * @param Committee $committee
     * @param string $email
     * @return bool
     */
    public function removeContactFromCommittee(Committee $committee, string $email): bool
    {
        $title = $this->getCommitteeTitle($committee);
        if (empty($title)) {
            return false;
        }
        return $this->removeContactFromList("Committee: {$title}", $email);
    }

    /**
     * Add a contact to a workgroup's list.
     *
     * @param WorkGroup $workGroup
     * @param string $email
     * @return bool
     */
    public function addContactToWorkGroup(WorkGroup $workGroup, string $email): bool
    {
        $title = $this->getWorkGroupTitle($workGroup);
        if (empty($title)) {
            return false;
        }
        return $this->addContactToList("WorkGroup: {$title}", $email);
    }

    /**
     * Remove a contact from a workgroup's list.
     *
     * @param WorkGroup $workGroup
     * @param string $email
     * @return bool
     */
    public function removeContactFromWorkGroup(WorkGroup $workGroup, string $email): bool
    {
        $title = $this->getWorkGroupTitle($workGroup);
        if (empty($title)) {
            return false;
        }
        return $this->removeContactFromList("WorkGroup: {$title}", $email);
    }

    /**
     * Get all emails in a list by title.
     *
     * @param string $listTitle
     * @return array
     */
    public function getContactsInList(string $listTitle): array
    {
        $this->initialize();
        $list = $this->listService->getListByTitle($listTitle);

        if ($list === null) {
            return [];
        }

        return $this->contactService->getContactEmailsInList($list['listId']);
    }

    /**
     * Get a contact by email.
     *
     * @param string $email
     * @return array|null
     */
    public function getContactByEmail(string $email): ?array
    {
        $this->initialize();
        return $this->contactService->getContactByEmail($email);
    }

    /**
     * Ensure a contact exists in HubSpot.
     *
     * @param string $email
     * @param string|null $firstName
     * @param string|null $lastName
     * @return array
     */
    public function ensureContactExists(string $email, ?string $firstName = null, ?string $lastName = null): array
    {
        $this->initialize();
        return $this->contactService->ensureContactExists($email, $firstName, $lastName);
    }

    // =========================================================================
    // HELPER METHODS
    // =========================================================================

    /**
     * Get the title for a committee in the configured language.
     *
     * @param Committee $committee
     * @return string|null
     */
    protected function getCommitteeTitle(Committee $committee): ?string
    {
        $language = $this->apiClient->getTitleLanguage();
        $originalLocale = LaravelLocalization::getCurrentLocale();

        LaravelLocalization::setLocale($language);

        try {
            // Force reload languages relationship to get fresh data
            $committee->load('languages');
            return $committee->title;
        } finally {
            LaravelLocalization::setLocale($originalLocale);
        }
    }

    /**
     * Get the title for a workgroup in the configured language.
     *
     * @param WorkGroup $workGroup
     * @return string|null
     */
    protected function getWorkGroupTitle(WorkGroup $workGroup): ?string
    {
        $language = $this->apiClient->getTitleLanguage();
        $originalLocale = LaravelLocalization::getCurrentLocale();

        LaravelLocalization::setLocale($language);

        try {
            // Force reload languages relationship to get fresh data
            $workGroup->load('languages');
            return $workGroup->title;
        } finally {
            LaravelLocalization::setLocale($originalLocale);
        }
    }

    /**
     * Get the API client instance.
     *
     * @return HubSpotApiClient
     */
    public function getApiClient(): HubSpotApiClient
    {
        return $this->apiClient;
    }

    /**
     * Get the orchestrator instance.
     *
     * @return HubSpotSyncOrchestrator
     */
    public function getOrchestrator(): HubSpotSyncOrchestrator
    {
        return $this->orchestrator;
    }

    /**
     * Get the list service instance.
     *
     * @return HubSpotListService
     */
    public function getListService(): HubSpotListService
    {
        return $this->listService;
    }

    /**
     * Get the contact service instance.
     *
     * @return HubSpotContactService
     */
    public function getContactService(): HubSpotContactService
    {
        return $this->contactService;
    }
}
