<?php
namespace EasyChat\Library\Cms;

use EasyChat\Library\CustomerContactService;
use EasyChat\Library\CustomerMergeService;
use EasyChat\Library\Logger;
use EasyChat\Model\Customer;
use EasyChat\Model\Setting;

final class CmsVisitorIdentityService
{
    private $registry; private $db; private $prefix; private $secret;

    public function __construct($registry)
    {
        $this->registry = $registry; $this->db = $registry->get('db'); $this->prefix = easychat_db_prefix();
        $this->secret = (string)(new Setting($registry))->get('chat_install_secret', '');
    }

    public function bindAssertionToChat(string $assertion, string $session_id, int $chat_id): array
    {
        if ($assertion === '') return array('authenticated' => false, 'state' => 'anonymous');
        $verified = CmsVisitorIdentityAssertion::verify($assertion, $session_id, $this->secret);
        if (empty($verified['valid'])) return array('authenticated' => false, 'state' => 'invalid', 'error' => $verified['error']);
        if ($chat_id <= 0) return array('authenticated' => true, 'state' => 'verified_virtual', 'identity' => $verified['identity']);

        $identity = (array)$verified['identity'];
        $repo = new CmsCustomerIdentityRepository($this->db, $this->prefix, $this->secret);
        $lock_name = 'easychat_cms_identity_' . substr($repo->identityHash($identity['provider'], $identity['scope'], $identity['subject']), 0, 40);
        $lock = $this->db->query("SELECT GET_LOCK('" . $this->db->escape($lock_name) . "', 3) AS `locked`");
        if ((int)($lock->row['locked'] ?? 0) !== 1) return array('authenticated' => false, 'state' => 'busy', 'error' => 'identity_binding_busy');

        try {
            $this->db->query('START TRANSACTION');
            $chat_query = $this->db->query("SELECT * FROM `{$this->prefix}sessions` WHERE `chat_id`=" . (int)$chat_id . " AND `session_id`='" . $this->db->escape($session_id) . "' LIMIT 1 FOR UPDATE");
            $chat = (array)($chat_query->row ?? array());
            if (!$chat) throw new \RuntimeException('chat_not_found');

            $mapped = $repo->find($identity['provider'], $identity['scope'], $identity['subject'], true);
            $bound_identity_id = (int)($chat['cms_identity_id'] ?? 0);
            if ($bound_identity_id > 0 && (int)($mapped['identity_id'] ?? 0) !== $bound_identity_id) {
                 
                 
                throw new \RuntimeException('identity_changed');
            }
            $customer_id = (int)($mapped['customer_id'] ?? 0);
            if ($customer_id <= 0) $customer_id = (new Customer($this->registry))->ensureCustomerForChat($chat_id);
            if ($customer_id > 0) {
                $resolved_customer_id = (new CustomerMergeService($this->registry))->resolveMergedCustomerId($customer_id);
                if ($resolved_customer_id > 0 && $resolved_customer_id !== $customer_id) {
                    $customer_id = $resolved_customer_id;
                    if (!empty($mapped['identity_id'])) $repo->reassignCustomer((int)$mapped['identity_id'], $customer_id, date('Y-m-d H:i:s'));
                }
            }
            if ($customer_id <= 0) throw new \RuntimeException('customer_not_found');

             
             
            $mapping = $repo->save($customer_id, $identity['provider'], $identity['scope'], $identity['subject'], date('Y-m-d H:i:s'));
            $identity_id = (int)($mapping['identity_id'] ?? 0);
            if ($identity_id <= 0) throw new \RuntimeException('identity_mapping_not_saved');
            $this->db->query("UPDATE `{$this->prefix}sessions` SET `customer_id`=" . (int)$customer_id . ", `cms_identity_id`=" . $identity_id . ", `cms_identity_bound_at`=NOW() WHERE `chat_id`=" . (int)$chat_id);
            if ($identity['name'] !== '') {
                $this->db->query("UPDATE `{$this->prefix}sessions` SET `customer_name`='" . $this->db->escape($identity['name']) . "' WHERE `chat_id`=" . (int)$chat_id);
                $this->db->query("UPDATE `{$this->prefix}customers` SET `display_name`='" . $this->db->escape($identity['name']) . "', `date_modified`=NOW() WHERE `customer_id`=" . (int)$customer_id);
            }
            $this->db->query('COMMIT');
            $result = array('authenticated' => true, 'state' => 'bound', 'customer_id' => $customer_id, 'identity_id' => $identity_id, 'identity' => $identity);
        } catch (\Throwable $e) {
            $this->db->query('ROLLBACK');
            return array('authenticated' => false, 'state' => 'failed', 'error' => $e->getMessage());
        } finally {
            $this->db->query("SELECT RELEASE_LOCK('" . $this->db->escape($lock_name) . "')");
        }

         
         
         
        try {
            (new CustomerContactService($this->registry))->recordCmsConfirmedContactsForChat($chat_id, $identity['email'], $identity['phone'], $identity['provider']);
        } catch (\Throwable $e) {
            Logger::warning('cms_identity_contact_enrichment_failed fingerprint=' . substr(hash('sha256', $e->getMessage()), 0, 12), 'customer.log');
            $result['contact_enrichment'] = 'retry_pending';
        }
        return $result;
    }
}
