<?php
namespace EasyChat\Library\Messenger;

use EasyChat\Library\CustomerContactService;
use EasyChat\Model\Messenger;
use EasyChat\Model\Session;







final class WhatsAppPersonalIdentityRepository {
    private $registry;
    private $db;
    private $prefix;

    public function __construct($registry) {
        $this->registry = $registry;
        $this->db = $registry->get('db');
        $this->prefix = easychat_db_prefix();
    }

    public function rememberMapping(int $channel_id, string $phone_jid, string $lid_jid, string $evidence = 'protocol_mapping'): bool {
        $phone_jid = $this->phoneJid($phone_jid);
        $lid_jid = $this->lidJid($lid_jid);
        if ($channel_id <= 0 || $phone_jid === '' || $lid_jid === '') {
            return false;
        }
         
         
         
        $known = $this->resolve($channel_id, $phone_jid);
        if (!$known) {
            $known = $this->resolve($channel_id, $lid_jid);
        }
        $name = $this->label((string)($known['display_name'] ?? ''));
        $avatar_url = $this->avatarUrl((string)($known['avatar_url'] ?? ''));
        $this->upsert($channel_id, $phone_jid, $phone_jid, $lid_jid, $name, $avatar_url, $evidence);
        $this->upsert($channel_id, $lid_jid, $phone_jid, $lid_jid, $name, $avatar_url, $evidence);
        $this->repairExistingContact($channel_id, $phone_jid, $lid_jid, $name, $avatar_url);
        return true;
    }

    public function rememberProfile(int $channel_id, string $jid, string $name, string $avatar_url = '', string $phone_jid = '', string $lid_jid = ''): bool {
        $jid = $this->jid($jid);
        if ($channel_id <= 0 || $jid === '') {
            return false;
        }
        $name = $this->label($name);
        $avatar_url = $this->avatarUrl($avatar_url);
        $phone_jid = $this->phoneJid($phone_jid);
        $lid_jid = $this->lidJid($lid_jid);
        if ($phone_jid === '' && $this->phoneJid($jid) !== '') {
            $phone_jid = $jid;
        }
        if ($lid_jid === '' && $this->lidJid($jid) !== '') {
            $lid_jid = $jid;
        }
        $this->upsert($channel_id, $jid, $phone_jid, $lid_jid, $name, $avatar_url, 'profile');
        if ($phone_jid !== '' && $lid_jid !== '') {
            $this->rememberMapping($channel_id, $phone_jid, $lid_jid, 'history_mapping');
        }
        $this->repairExistingContact($channel_id, $phone_jid ?: $jid, $lid_jid ?: $jid, $name, $avatar_url);
        return true;
    }

    public function resolve(int $channel_id, string $jid): array {
        $jid = $this->jid($jid);
        if ($channel_id <= 0 || $jid === '') {
            return [];
        }
        $jid_e = $this->db->escape($jid);
        $result = $this->db->query(
            "SELECT * FROM `{$this->prefix}whatsapp_personal_identities`
             WHERE `channel_id` = {$channel_id}
               AND (`identity_jid` = '{$jid_e}' OR `phone_jid` = '{$jid_e}' OR `lid_jid` = '{$jid_e}')
             ORDER BY (`identity_jid` = '{$jid_e}') DESC,
                      (`display_name` <> '') DESC,
                      `date_modified` DESC
             LIMIT 4"
        );
        $rows = is_array($result->rows ?? null) ? $result->rows : [];
        if (!$rows && is_array($result->row ?? null) && $result->row) {
            $rows[] = $result->row;
        }
        if (!$rows) {
            return [];
        }
        $resolved = $rows[0];
        foreach ($rows as $row) {
            foreach (['phone_jid', 'lid_jid', 'display_name', 'avatar_url'] as $field) {
                if (trim((string)($resolved[$field] ?? '')) === '' && trim((string)($row[$field] ?? '')) !== '') {
                    $resolved[$field] = (string)$row[$field];
                }
            }
        }
        return $resolved;
    }

    public function phoneFromPair(string $first, string $second): string {
        $phone = $this->phoneJid($first) ?: $this->phoneJid($second);
        $lid = $this->lidJid($first) ?: $this->lidJid($second);
        if ($phone === '' || $lid === '') {
            return '';
        }
        return '+' . substr($phone, 0, strpos($phone, '@'));
    }

    




    public function confirmedPhone(int $channel_id, string $first, string $second = ''): string {
        $direct = $this->phoneFromPair($first, $second);
        if ($direct !== '') {
            return $direct;
        }
        foreach (array_unique(array_filter([$this->jid($first), $this->jid($second)])) as $jid) {
            $resolved = $this->resolve($channel_id, $jid);
            $phone_jid = $this->phoneJid((string)($resolved['phone_jid'] ?? ''));
            $lid_jid = $this->lidJid((string)($resolved['lid_jid'] ?? ''));
            if ($phone_jid !== '' && $lid_jid !== '') {
                return '+' . substr($phone_jid, 0, strpos($phone_jid, '@'));
            }
        }
        return '';
    }

    private function repairExistingContact(int $channel_id, string $phone_jid, string $lid_jid, string $name, string $avatar_url): void {
        $model = new Messenger($this->registry);
        $contact = [];
        foreach (array_unique(array_filter([$lid_jid, $phone_jid])) as $candidate) {
            $contact = $model->findContact($channel_id, $candidate);
            if (!$contact) {
                $contact = $model->findContactByExternalChat($channel_id, $candidate);
            }
            if ($contact) {
                break;
            }
        }
        if (!$contact) {
            return;
        }
        if ($phone_jid !== '' && $lid_jid !== ''
            && hash_equals((string)($contact['external_user_id'] ?? ''), $phone_jid)) {
            $lid_e = $this->db->escape($lid_jid);
            $duplicate = $this->db->query(
                "SELECT `contact_id` FROM `{$this->prefix}messenger_contacts`
                 WHERE `channel_id` = {$channel_id} AND `external_user_id` = '{$lid_e}' LIMIT 1"
            )->row;
            if (!$duplicate) {
                $phone_e = $this->db->escape($phone_jid);
                $this->db->query(
                    "UPDATE `{$this->prefix}messenger_contacts`
                     SET `external_user_id` = '{$lid_e}',
                         `external_chat_id` = IF(`external_chat_id` = '{$phone_e}', '{$lid_e}', `external_chat_id`),
                         `date_modified` = NOW()
                     WHERE `contact_id` = " . (int)$contact['contact_id']
                );
                $contact['external_user_id'] = $lid_jid;
                if ((string)($contact['external_chat_id'] ?? '') === $phone_jid) {
                    $contact['external_chat_id'] = $lid_jid;
                }
            }
        }
        $metadata = json_decode((string)($contact['metadata_json'] ?? '{}'), true);
        $metadata = is_array($metadata) ? $metadata : [];
        if ($phone_jid !== '' && $lid_jid !== '') {
            $metadata['whatsapp_phone_jid'] = $phone_jid;
            $metadata['whatsapp_lid_jid'] = $lid_jid;
            $metadata['whatsapp_identity_evidence'] = 'protocol_mapping';
        }
        $display = $name !== '' ? $name : (string)($contact['display_name'] ?? '');
        $model->upsertContact(
            $channel_id,
            WhatsAppPersonalProvider::PROVIDER,
            (string)$contact['external_user_id'],
            (string)$contact['external_chat_id'],
            $display,
            (string)($contact['username'] ?? ''),
            $avatar_url !== '' ? $avatar_url : (string)($contact['profile_url'] ?? ''),
            (int)($contact['chat_id'] ?? 0),
            $metadata,
            true
        );
        $chat_id = (int)($contact['chat_id'] ?? 0);
        if ($chat_id > 0 && $name !== '') {
            $session = (new Session($this->registry))->getSessionById($chat_id);
            $current = trim((string)($session['customer_name'] ?? ''));
            if ($current === '' || strpos($current, 'WhatsApp ') === 0 || $current === 'WhatsApp') {
                (new Session($this->registry))->updateSession($chat_id, ['customer_name' => $name], false);
            }
        }
        if ($chat_id > 0 && $phone_jid !== '' && $lid_jid !== '') {
            $phone = $this->phoneFromPair($phone_jid, $lid_jid);
            if ($phone !== '') {
                (new CustomerContactService($this->registry))->recordProviderConfirmedPhoneForChat(
                    $chat_id,
                    $phone,
                    'whatsapp_protocol_mapping',
                    WhatsAppPersonalProvider::PROVIDER
                );
            }
        }
    }

    private function upsert(int $channel_id, string $identity_jid, string $phone_jid, string $lid_jid, string $name, string $avatar_url, string $evidence): void {
        $this->db->query(
            "INSERT INTO `{$this->prefix}whatsapp_personal_identities`
                (`channel_id`, `identity_jid`, `phone_jid`, `lid_jid`, `display_name`, `avatar_url`, `evidence`, `date_added`, `date_modified`)
             VALUES ({$channel_id},
                '" . $this->db->escape($identity_jid) . "',
                '" . $this->db->escape($phone_jid) . "',
                '" . $this->db->escape($lid_jid) . "',
                '" . $this->db->escape($name) . "',
                '" . $this->db->escape($avatar_url) . "',
                '" . $this->db->escape(substr(preg_replace('/[^a-z0-9_]/', '', strtolower($evidence)), 0, 32)) . "',
                NOW(), NOW())
             ON DUPLICATE KEY UPDATE
                `phone_jid` = IF(VALUES(`phone_jid`) <> '', VALUES(`phone_jid`), `phone_jid`),
                `lid_jid` = IF(VALUES(`lid_jid`) <> '', VALUES(`lid_jid`), `lid_jid`),
                `display_name` = IF(VALUES(`display_name`) <> '', VALUES(`display_name`), `display_name`),
                `avatar_url` = IF(VALUES(`avatar_url`) <> '', VALUES(`avatar_url`), `avatar_url`),
                `evidence` = IF(VALUES(`evidence`) <> '', VALUES(`evidence`), `evidence`),
                `date_modified` = NOW()"
        );
    }

    private function jid(string $jid): string {
        $jid = strtolower(trim($jid));
        $jid = (string)preg_replace('/:[0-9]+@/', '@', $jid);
        return preg_match('/^[a-z0-9_.-]+(?::[0-9]+)?@(s\.whatsapp\.net|lid|g\.us|broadcast)$/D', $jid) === 1
            ? substr($jid, 0, 191)
            : '';
    }

    private function phoneJid(string $jid): string {
        $jid = strtolower(trim($jid));
        $jid = (string)preg_replace('/:[0-9]+@/', '@', $jid);
        return preg_match('/^[1-9][0-9]{0,19}@s\.whatsapp\.net$/D', $jid) === 1 ? $jid : '';
    }

    private function lidJid(string $jid): string {
        $jid = strtolower(trim($jid));
        $jid = (string)preg_replace('/:[0-9]+@/', '@', $jid);
        return preg_match('/^[1-9][0-9]{0,19}@lid$/D', $jid) === 1 ? $jid : '';
    }

    private function label(string $name): string {
        $name = trim((string)preg_replace('/\s+/u', ' ', strip_tags($name)));
        return mb_substr($name, 0, 191, 'UTF-8');
    }

    private function avatarUrl(string $url): string {
        $url = trim($url);
        if ($url === '' || strlen($url) > 1024) {
            return '';
        }
        $parts = parse_url($url);
        $host = strtolower((string)($parts['host'] ?? ''));
        return (string)($parts['scheme'] ?? '') === 'https'
            && (($host === 'whatsapp.net') || substr($host, -13) === '.whatsapp.net' || $host === 'whatsapp.com' || substr($host, -13) === '.whatsapp.com')
            && empty($parts['user']) && empty($parts['pass']) && empty($parts['fragment'])
                ? $url
                : '';
    }
}
