<?php

declare(strict_types=1);

function registerBitrixAiBot(): array
{
    return registerBitrixBot([
        'CODE' => (string) config('BITRIX_AI_BOT_CODE', 'darex_ai_direct_bot'),
        'TYPE' => (string) config('BITRIX_AI_BOT_TYPE', 'H'),
        'NAME' => (string) config('BITRIX_AI_BOT_NAME', 'Darex AI Direct'),
        'OPENLINE' => 'N',
    ]);
}

function registerBitrixOpenLineBot(): array
{
    return registerBitrixBot([
        'CODE' => (string) config('BITRIX_OPENLINE_BOT_CODE', 'darex_ai_openline_bot'),
        'TYPE' => (string) config('BITRIX_OPENLINE_BOT_TYPE', 'H'),
        'NAME' => (string) config('BITRIX_OPENLINE_BOT_NAME', 'Darex AI OpenLine'),
        'OPENLINE' => 'Y',
    ]);
}

function registerBitrixBot(array $bot): array
{
    $handlerUrl = appUrl('bot_handler.php');
    $params = [
        'CODE' => (string) $bot['CODE'],
        'TYPE' => (string) $bot['TYPE'],
        'EVENT_HANDLER' => $handlerUrl,
        'EVENT_MESSAGE_ADD' => $handlerUrl,
        'EVENT_WELCOME_MESSAGE' => $handlerUrl,
        'EVENT_BOT_DELETE' => $handlerUrl,
        'PROPERTIES' => [
            'NAME' => (string) $bot['NAME'],
            'LAST_NAME' => 'Assistant',
            'COLOR' => 'BLUE',
            'EMAIL' => 'ai@darex-moto.ru',
            'WORK_POSITION' => 'AI assistant',
            'PERSONAL_BIRTHDAY' => '2026-01-01',
        ],
    ];

    if (($bot['OPENLINE'] ?? 'N') === 'Y') {
        $params['OPENLINE'] = 'Y';
    }

    return bitrixCall('imbot.register', $params);
}

function unregisterBitrixAiBot(?int $botId = null): array
{
    $botId = $botId ?: (int) config('BITRIX_AI_BOT_ID', 0);
    if ($botId <= 0) {
        throw new RuntimeException('BITRIX_AI_BOT_ID is not configured.');
    }

    return bitrixCall('imbot.unregister', [
        'BOT_ID' => $botId,
    ]);
}

function unregisterBitrixOpenLineBot(?int $botId = null): array
{
    $botId = $botId ?: (int) config('BITRIX_OPENLINE_BOT_ID', 0);
    if ($botId <= 0) {
        throw new RuntimeException('BITRIX_OPENLINE_BOT_ID is not configured.');
    }

    return bitrixCall('imbot.unregister', [
        'BOT_ID' => $botId,
    ]);
}

function updateBitrixAiBot(?int $botId = null): array
{
    $botId = $botId ?: (int) config('BITRIX_AI_BOT_ID', 0);
    if ($botId <= 0) {
        throw new RuntimeException('BITRIX_AI_BOT_ID is not configured.');
    }

    $handlerUrl = appUrl('bot_handler.php');

    return bitrixCall('imbot.update', [
        'BOT_ID' => $botId,
        'FIELDS' => [
            'EVENT_HANDLER' => $handlerUrl,
            'EVENT_MESSAGE_ADD' => $handlerUrl,
            'EVENT_WELCOME_MESSAGE' => $handlerUrl,
            'EVENT_BOT_DELETE' => $handlerUrl,
            'PROPERTIES' => [
                'NAME' => (string) config('BITRIX_AI_BOT_NAME', 'Darex AI Direct'),
                'LAST_NAME' => 'Assistant',
                'COLOR' => 'BLUE',
                'EMAIL' => 'ai@darex-moto.ru',
                'WORK_POSITION' => 'AI assistant',
            ],
        ],
    ]);
}

function sendBitrixBotMessage(string $dialogId, string $message, ?int $botId = null): array
{
    $botId = $botId ?: (int) config('BITRIX_AI_BOT_ID', 0);
    if ($botId <= 0) {
        throw new RuntimeException('Bitrix bot id is not configured.');
    }

    return bitrixCall('imbot.message.add', [
        'BOT_ID' => $botId,
        'DIALOG_ID' => $dialogId,
        'MESSAGE' => $message,
    ]);
}

function sendBitrixNotificationMessage(string $dialogId, string $message, ?int $botId = null): array
{
    $botId = (int) ($botId ?? 0);
    if ($botId > 0) {
        return [
            'sender' => 'bot',
            'bot_id' => $botId,
            'response' => sendBitrixBotMessage($dialogId, $message, $botId),
        ];
    }

    return [
        'sender' => 'application_user',
        'bot_id' => null,
        'response' => bitrixCall('im.message.add', [
            'DIALOG_ID' => $dialogId,
            'MESSAGE' => $message,
        ]),
    ];
}

function normalizeBitrixBotPayload(array $payload): array
{
    $event = strtoupper((string) firstPayloadValue($payload, [
        'event',
        'EVENT',
        'data.event',
        'data.EVENT',
    ], ''));

    $dialogId = (string) firstPayloadValue($payload, [
        'data.PARAMS.DIALOG_ID',
        'data.PARAMS.dialogId',
        'data.PARAMS.TO_CHAT_ID',
        'PARAMS.DIALOG_ID',
        'PARAMS.TO_CHAT_ID',
        'DIALOG_ID',
    ], '');

    $chatId = (string) firstPayloadValue($payload, [
        'data.PARAMS.CHAT_ID',
        'data.PARAMS.TO_CHAT_ID',
        'PARAMS.CHAT_ID',
        'PARAMS.TO_CHAT_ID',
        'CHAT_ID',
    ], '');

    if ($dialogId === '' && $chatId !== '') {
        $dialogId = 'chat' . preg_replace('/\D+/', '', $chatId);
    }

    return [
        'event' => $event,
        'bot_id' => (string) firstPayloadValue($payload, [
            'data.PARAMS.BOT_ID',
            'PARAMS.BOT_ID',
            'BOT_ID',
        ], firstBotIdFromPayload($payload)),
        'open_line_id' => detectOpenLineId($payload),
        'deal_id' => detectDealId($payload),
        'dialog_id' => $dialogId,
        'chat_id' => $chatId,
        'chat_title' => (string) firstPayloadValue($payload, [
            'data.PARAMS.CHAT_TITLE',
            'PARAMS.CHAT_TITLE',
            'CHAT_TITLE',
        ], ''),
        'message_id' => (string) firstPayloadValue($payload, [
            'data.PARAMS.MESSAGE_ID',
            'data.PARAMS.ID',
            'PARAMS.MESSAGE_ID',
            'PARAMS.ID',
            'MESSAGE_ID',
            'ID',
        ], ''),
        'author_id' => (string) firstPayloadValue($payload, [
            'data.PARAMS.AUTHOR_ID',
            'data.PARAMS.FROM_USER_ID',
            'PARAMS.AUTHOR_ID',
            'PARAMS.FROM_USER_ID',
            'AUTHOR_ID',
            'FROM_USER_ID',
        ], ''),
        'message' => trim(strip_tags((string) firstPayloadValue($payload, [
            'data.PARAMS.MESSAGE',
            'data.PARAMS.MESSAGE_ORIGINAL',
            'PARAMS.MESSAGE',
            'PARAMS.MESSAGE_ORIGINAL',
            'MESSAGE',
            'TEXT',
        ], ''))),
    ];
}

function detectDealId(array $payload): string
{
    $dealId = normalizeBitrixId(firstPayloadValue($payload, [
        'data.PARAMS.DEAL_ID',
        'data.PARAMS.CRM_DEAL_ID',
        'data.PARAMS.CRM.DEAL_ID',
        'data.PARAMS.SESSION.DEAL_ID',
        'data.PARAMS.SESSION.CRM_DEAL_ID',
        'PARAMS.DEAL_ID',
        'PARAMS.CRM_DEAL_ID',
        'DEAL_ID',
        'CRM_DEAL_ID',
    ], ''));

    if ($dealId !== '') {
        return $dealId;
    }

    $entityType = strtoupper((string) firstPayloadValue($payload, [
        'data.PARAMS.CRM_ENTITY_TYPE',
        'data.PARAMS.ENTITY_TYPE',
        'data.PARAMS.CRM.ENTITY_TYPE',
        'PARAMS.CRM_ENTITY_TYPE',
        'PARAMS.ENTITY_TYPE',
        'CRM_ENTITY_TYPE',
        'ENTITY_TYPE',
    ], ''));

    if (in_array($entityType, ['DEAL', 'D'], true)) {
        return normalizeBitrixId(firstPayloadValue($payload, [
            'data.PARAMS.CRM_ENTITY_ID',
            'data.PARAMS.ENTITY_ID',
            'data.PARAMS.CRM.ENTITY_ID',
            'PARAMS.CRM_ENTITY_ID',
            'PARAMS.ENTITY_ID',
            'CRM_ENTITY_ID',
            'ENTITY_ID',
        ], ''));
    }

    return normalizeBitrixId(findPayloadValueByKey($payload, ['DEAL_ID', 'CRM_DEAL_ID']));
}

function normalizeBitrixId($value): string
{
    $value = trim((string) $value);
    if ($value === '') {
        return '';
    }

    if (preg_match('/\d+/', $value, $matches)) {
        return $matches[0];
    }

    return '';
}

function detectOpenLineId(array $payload): string
{
    $lineId = normalizeOpenLineId(firstPayloadValue($payload, [
        'data.PARAMS.OPEN_LINE_ID',
        'data.PARAMS.LINE_ID',
        'data.PARAMS.CONFIG_ID',
        'data.PARAMS.OL_ID',
        'data.PARAMS.SESSION.OPEN_LINE_ID',
        'data.PARAMS.SESSION.LINE_ID',
        'data.PARAMS.SESSION.CONFIG_ID',
        'PARAMS.OPEN_LINE_ID',
        'PARAMS.LINE_ID',
        'PARAMS.CONFIG_ID',
        'PARAMS.OL_ID',
        'OPEN_LINE_ID',
        'LINE_ID',
        'CONFIG_ID',
    ], ''));

    if ($lineId !== '') {
        return $lineId;
    }

    $lineId = extractOpenLineIdFromChatEntityId(firstPayloadValue($payload, [
        'data.PARAMS.CHAT_ENTITY_ID',
        'PARAMS.CHAT_ENTITY_ID',
        'CHAT_ENTITY_ID',
    ], ''));

    if ($lineId !== '') {
        return $lineId;
    }

    return '';
}

function extractOpenLineIdFromChatEntityId($value): string
{
    $value = trim((string) $value);
    if ($value === '') {
        return '';
    }

    $parts = explode('|', $value);
    if (count($parts) < 2) {
        return '';
    }

    return normalizeOpenLineId($parts[1]);
}

function normalizeOpenLineId($value): string
{
    $value = trim((string) $value);
    if ($value === '') {
        return '';
    }

    if (preg_match('/\d+/', $value, $matches)) {
        return $matches[0];
    }

    return '';
}

function configuredBitrixBotIds(): array
{
    return array_values(array_filter(array_unique([
        (string) config('BITRIX_AI_BOT_ID', ''),
        (string) config('BITRIX_OPENLINE_BOT_ID', ''),
    ]), static fn ($id) => $id !== '' && $id !== '0'));
}

function firstBotIdFromPayload(array $payload): string
{
    $bots = payloadValueArray($payload, 'data.BOT');
    if ($bots !== []) {
        $firstKey = array_key_first($bots);
        if ($firstKey !== null) {
            return (string) $firstKey;
        }
    }

    return '';
}

function firstPayloadValue(array $payload, array $paths, $default = null)
{
    foreach ($paths as $path) {
        $value = payloadValue($payload, $path);
        if ($value !== null && $value !== '') {
            return $value;
        }
    }

    return $default;
}

function payloadValue(array $payload, string $path)
{
    $current = $payload;
    foreach (explode('.', $path) as $part) {
        if (!is_array($current) || !array_key_exists($part, $current)) {
            return null;
        }
        $current = $current[$part];
    }

    return is_array($current) ? null : $current;
}

function payloadValueArray(array $payload, string $path): array
{
    $current = $payload;
    foreach (explode('.', $path) as $part) {
        if (!is_array($current) || !array_key_exists($part, $current)) {
            return [];
        }
        $current = $current[$part];
    }

    return is_array($current) ? $current : [];
}

function findPayloadValueByKey(array $payload, array $keys)
{
    $upperKeys = array_map('strtoupper', $keys);
    foreach ($payload as $key => $value) {
        if (in_array(strtoupper((string) $key), $upperKeys, true) && !is_array($value) && $value !== '') {
            return $value;
        }

        if (is_array($value)) {
            $found = findPayloadValueByKey($value, $keys);
            if ($found !== null && $found !== '') {
                return $found;
            }
        }
    }

    return null;
}
