<?php
namespace EasyChat\Library\Crm;

use EasyChat\Library\Queue\QueueManager;
use EasyChat\Library\Messenger\ChannelCatalog;
use EasyChat\Model\CrmConnection;
use EasyChat\Model\Setting;

final class CrmSyncService {
    private $registry;

    public function __construct($registry) { $this->registry = $registry; }

    public function enqueueIncoming(int $chat_id, int $message_id): int {
        if ($chat_id <= 0 || $message_id <= 0) return 0;
        $connections = (new CrmConnection($this->registry))->getActive();
        if (!$connections) return 0;
        $queue = new QueueManager($this->registry);
        $first_job = 0;
        foreach ($connections as $connection) {
            $job = $queue->pushUnique(
                'crm_conversation_sync',
                array('connection_id'=>(int)$connection['connection_id'],'chat_id'=>$chat_id,'message_id'=>$message_id),
                'crm:' . (string)$connection['provider'] . ':' . (int)$connection['connection_id'] . ':message:' . $message_id,
                0,
                4
            );
            if ($first_job <= 0) $first_job = $job;
        }
        return $first_job;
    }

    public function sync(int $connection_id, int $chat_id, int $message_id): void {
        $connection = (new CrmConnection($this->registry))->getById($connection_id, true);
        if (($connection['status'] ?? '') !== 'active') return;
        $db = $this->registry->get('db');
        $prefix = easychat_db_prefix();
        $lock_name = 'ec_crm_' . substr(hash('sha256', $prefix . ':' . $connection_id . ':' . $chat_id), 0, 40);
        $lock = $db->query("SELECT GET_LOCK('" . $db->escape($lock_name) . "', 5) AS `locked`");
        if ((int)($lock->row['locked'] ?? 0) !== 1) throw new \RuntimeException('crm_sync_busy');
        try {
            $existing = $db->query("SELECT `external_id`,`external_contact_id`,`origin_key`,`external_url`,`last_message_id` FROM `{$prefix}crm_conversation_links` WHERE `connection_id`={$connection_id} AND `chat_id`={$chat_id} LIMIT 1");
            if ($existing && $existing->row && (int)$existing->row['last_message_id'] >= $message_id) return;
            $conversation = $this->conversation($chat_id, $message_id);
            if (!$conversation) return;
            $conversation['origin_id'] = $connection_id . ':' . $chat_id;
            $conversation['origin_key'] = $this->originKey($connection_id, $chat_id);
            $conversation['message_marker'] = '[#ECM-' . strtoupper(substr(hash_hmac('sha256', $connection_id . '|' . $chat_id . '|' . $message_id, $this->installSecret()), 0, 16)) . ']';
            if ($existing && $existing->row) {
                $conversation['external_id'] = (string)$existing->row['external_id'];
                $conversation['external_contact_id'] = (string)$existing->row['external_contact_id'];
                $conversation['external_url'] = (string)$existing->row['external_url'];
                if ((string)$existing->row['origin_key'] !== '') $conversation['origin_key'] = (string)$existing->row['origin_key'];
            }
            $deliveries = new CrmDeliveryRepository($this->registry);
            $delivery = $deliveries->begin($connection_id, $chat_id, $message_id, 'append_message', $conversation['message_marker'], hash('sha256', (string)$conversation['summary']));
            if (($delivery['state'] ?? '') === 'succeeded') return;
            $conversation['delivery_state'] = (string)($delivery['state'] ?? 'inflight');
            $result = (new CrmProviderRegistry($this->registry))->get((string)$connection['provider'])->syncConversation($connection, $conversation);
            if (empty($result['success'])) {
                $deliveries->failed($connection_id, $chat_id, $message_id, 'append_message', (string)($result['error'] ?? 'crm_sync_failed'), !empty($result['outcome_unknown']), (int)($result['http_status'] ?? 0));
                throw new CrmSyncException((string)($result['error'] ?? 'crm_sync_failed'), !empty($result['retryable']));
            }
            $db->query("INSERT INTO `{$prefix}crm_conversation_links` (`connection_id`,`chat_id`,`entity_type`,`external_id`,`external_contact_id`,`origin_key`,`external_url`,`last_message_id`,`date_added`,`date_modified`) VALUES ({$connection_id},{$chat_id},'" . $db->escape((string)$result['entity_type']) . "','" . $db->escape((string)$result['external_id']) . "','" . $db->escape((string)($result['external_contact_id'] ?? '')) . "','" . $db->escape((string)$conversation['origin_key']) . "','" . $db->escape((string)$result['external_url']) . "',{$message_id},NOW(),NOW()) ON DUPLICATE KEY UPDATE `external_id`=VALUES(`external_id`),`external_contact_id`=VALUES(`external_contact_id`),`origin_key`=VALUES(`origin_key`),`external_url`=VALUES(`external_url`),`last_message_id`=GREATEST(`last_message_id`,VALUES(`last_message_id`)),`date_modified`=NOW()");
            $deliveries->succeeded($connection_id, $chat_id, $message_id, 'append_message', (string)($result['external_operation_id'] ?? ''));
        } finally {
            $db->query("SELECT RELEASE_LOCK('" . $db->escape($lock_name) . "')");
        }
    }

    private function conversation(int $chat_id, int $message_id): array {
        $db = $this->registry->get('db');
        $prefix = easychat_db_prefix();
        $query = $db->query("SELECT s.`customer_id`,s.`customer_name`,s.`source_provider`,m.`text` FROM `{$prefix}sessions` s JOIN `{$prefix}messages` m ON m.`message_id`={$message_id} AND m.`chat_id`=s.`chat_id` WHERE s.`chat_id`={$chat_id} AND m.`author`=1 LIMIT 1");
        if (!$query || !$query->row) return array();
        $row = $query->row;
        $contacts = array('phone' => '', 'email' => '');
        $customer_id = (int)($row['customer_id'] ?? 0);
        if ($customer_id > 0) {
            $contact_query = $db->query("SELECT `type`,`value` FROM `{$prefix}customer_contact_points` WHERE `customer_id`={$customer_id} AND `is_primary`=1 AND `type` IN ('phone','email')");
            foreach ((array)$contact_query->rows as $contact) $contacts[(string)$contact['type']] = (string)$contact['value'];
        }
        $name = trim((string)$row['customer_name']) ?: 'Новый клиент';
        $source = strtolower((string)$row['source_provider']) ?: 'widget';
        $text = trim(urldecode((string)$row['text']));
        $chat_url = rtrim((string)HTTP_SERVER, '/') . '/index.php?route=index&chat_id=' . $chat_id;
        return array(
            'title' => $name . ' — ' . $this->sourceLabel($source),
            'customer_name' => $name,
            'phone' => $contacts['phone'],
            'email' => $contacts['email'],
            'summary' => $text,
            'source_description' => 'Источник: ' . $this->sourceLabel($source) . "\nДиалог EasyChat: " . $chat_url,
            'source_label' => $this->sourceLabel($source),
            'chat_url' => $chat_url,
        );
    }

    private function installSecret(): string {
        return (string)(new Setting($this->registry))->get('chat_install_secret', 'easychat-crm');
    }

    private function originKey(int $connection_id, int $chat_id): string {
        return 'EC1-' . strtoupper(substr(hash_hmac('sha256', $connection_id . '|' . $chat_id, $this->installSecret()), 0, 20));
    }

    private function sourceLabel(string $source): string {
        return ChannelCatalog::label($source);
    }
}
