<?php

declare(strict_types=1);

function buildSystemPrompt(array $context = []): string
{
    $prompts = loadPromptsFromBitrixLists();
    $parts = [];
    $openLineId = normalizePromptOpenLineId($context['open_line_id'] ?? '');

    foreach ($prompts['system'] as $prompt) {
        if (promptMatchesOpenLine($prompt, $openLineId)) {
            $parts[] = promptItemText($prompt);
        }
    }

    foreach ($prompts['corrections'] as $prompt) {
        if (promptMatchesOpenLine($prompt, $openLineId)) {
            $parts[] = promptItemText($prompt);
        }
    }

    return implode("\n\n", array_filter(array_map('trim', $parts)));
}

function loadPromptsFromBitrixLists(): array
{
    $cacheFile = (string) config('PROMPT_CACHE_FILE');
    $ttl = (int) config('PROMPT_CACHE_TTL', 300);

    $cached = readJsonFile($cacheFile, []);
    if (($cached['version'] ?? 0) === 2 && ($cached['expires_at'] ?? 0) > time() && isset($cached['data'])) {
        return is_array($cached['data']) ? $cached['data'] : ['system' => [], 'corrections' => []];
    }

    $data = [
        'system' => loadPromptList(
            (string) config('SYSTEM_PROMPTS_LIST_CODE'),
            (string) config('SYSTEM_PROMPT_TEXT_PROPERTY', 'PROPERTY_269'),
            (string) config('SYSTEM_PROMPT_OPEN_LINE_PROPERTY', ''),
            (string) config('SYSTEM_PROMPT_ACTIVE_PROPERTY', 'PROPERTY_273')
        ),
        'corrections' => loadPromptList(
            (string) config('CORRECTION_PROMPTS_LIST_CODE'),
            (string) config('CORRECTION_PROMPT_TEXT_PROPERTY', 'PROPERTY_287'),
            (string) config('CORRECTION_PROMPT_OPEN_LINE_PROPERTY', ''),
            (string) config('CORRECTION_PROMPT_ACTIVE_PROPERTY', 'PROPERTY_291')
        ),
    ];

    writeJsonFile($cacheFile, [
        'version' => 2,
        'expires_at' => time() + $ttl,
        'data' => $data,
    ]);

    return $data;
}

function loadPromptList(
    string $listCode,
    string $textProperty,
    string $openLineProperty = '',
    string $activeProperty = ''
): array
{
    if ($listCode === '') {
        return [];
    }

    try {
        $list = findBitrixListByCode($listCode);
        if ($list === null) {
            logMessage('warning', 'Bitrix prompt list not found', ['code' => $listCode]);
            return [];
        }

        $response = bitrixCallRaw('lists.element.get', [
            'IBLOCK_TYPE_ID' => (string) ($list['_IBLOCK_TYPE_ID'] ?? 'lists'),
            'IBLOCK_ID' => $list['ID'],
            'FILTER' => [
                'ACTIVE' => 'Y',
            ],
        ]);

        if (isset($response['error'])) {
            logMessage('warning', 'Cannot load prompt list elements', [
                'code' => $listCode,
                'response' => $response,
            ]);
            return [];
        }

        $prompts = [];
        foreach (($response['result'] ?? []) as $element) {
            $element = (array) $element;
            if (!isPromptElementActive($element, $activeProperty)) {
                continue;
            }

            $text = extractPromptTextFromElement($element, $textProperty);
            if ($text !== '') {
                $prompts[] = [
                    'id' => (string) ($element['ID'] ?? ''),
                    'name' => (string) ($element['NAME'] ?? ''),
                    'text' => $text,
                    'open_line_ids' => extractPromptOpenLineIdsFromElement($element, $openLineProperty),
                ];
            }
        }

        return $prompts;
    } catch (Throwable $exception) {
        logMessage('warning', 'Prompt list load failed', [
            'code' => $listCode,
            'error' => $exception->getMessage(),
        ]);

        return [];
    }
}

function isPromptElementActive(array $element, string $activeProperty): bool
{
    $activeProperty = trim($activeProperty);
    if ($activeProperty === '') {
        return true;
    }

    $value = extractPromptPropertyValueFromElement($element, $activeProperty);
    if ($value === '') {
        return true;
    }

    $normalized = function_exists('mb_strtolower')
        ? mb_strtolower(trim($value), 'UTF-8')
        : strtolower(trim($value));
    $activeValues = ['y', 'yes', 'true', '1', 'да', '253', '273'];
    $inactiveValues = ['n', 'no', 'false', '0', 'нет', '255', '275'];

    if (in_array($normalized, $inactiveValues, true)) {
        return false;
    }

    if (in_array($normalized, $activeValues, true)) {
        return true;
    }

    return true;
}

function extractPromptOpenLineIdsFromElement(array $element, string $openLineProperty): array
{
    $openLineProperty = trim($openLineProperty);
    if ($openLineProperty === '') {
        return [];
    }

    $value = extractPromptPropertyValueFromElement($element, $openLineProperty);

    return normalizePromptOpenLineIds($value);
}

function promptMatchesOpenLine($prompt, string $openLineId): bool
{
    if (!is_array($prompt)) {
        return true;
    }

    $promptLineIds = normalizePromptOpenLineIds($prompt['open_line_ids'] ?? []);
    if ($promptLineIds === []) {
        return true;
    }

    if ($openLineId === '') {
        return false;
    }

    return in_array($openLineId, $promptLineIds, true);
}

function promptItemText($prompt): string
{
    if (is_array($prompt)) {
        return trim((string) ($prompt['text'] ?? ''));
    }

    return trim((string) $prompt);
}

function normalizePromptOpenLineIds($value): array
{
    if (is_array($value)) {
        $ids = [];
        foreach ($value as $item) {
            foreach (normalizePromptOpenLineIds($item) as $id) {
                $ids[] = $id;
            }
        }

        return array_values(array_unique($ids));
    }

    $value = trim((string) $value);
    if ($value === '') {
        return [];
    }

    $parts = preg_split('/\s*\/\s*/u', $value) ?: [];
    $ids = [];
    foreach ($parts as $part) {
        preg_match_all('/\d+/', $part, $matches);
        foreach (($matches[0] ?? []) as $id) {
            $ids[] = (string) $id;
        }
    }

    return array_values(array_unique($ids));
}

function normalizePromptOpenLineId($value): string
{
    $ids = normalizePromptOpenLineIds($value);

    return $ids[0] ?? '';
}

function findBitrixListByCode(string $listCode): ?array
{
    foreach (['lists', 'bitrix_processes'] as $iblockTypeId) {
        $response = bitrixCallRaw('lists.get', [
            'IBLOCK_TYPE_ID' => $iblockTypeId,
        ]);

        foreach (($response['result'] ?? []) as $list) {
            if ((string) ($list['CODE'] ?? '') === $listCode) {
                $list = (array) $list;
                $list['_IBLOCK_TYPE_ID'] = $iblockTypeId;

                return $list;
            }
        }
    }

    return null;
}

function extractPromptTextFromElement(array $element, string $textProperty): string
{
    $propertyValues = (array) ($element['PROPERTY_VALUES'] ?? []);
    $text = extractPromptPropertyValueFromElement($element, $textProperty);

    if ($text === '') {
        logMessage('warning', 'Prompt text property is empty', [
            'element_id' => $element['ID'] ?? null,
            'element_name' => $element['NAME'] ?? null,
            'property' => $textProperty,
            'available_element_keys' => array_keys($element),
            'available_properties' => array_keys($propertyValues),
        ]);
    }

    return $text;
}

function extractPromptPropertyValueFromElement(array $element, string $property): string
{
    $propertyValues = (array) ($element['PROPERTY_VALUES'] ?? []);
    $value = normalizePromptPropertyValue($element[$property] ?? null);

    if ($value === '') {
        $value = normalizePromptPropertyValue($propertyValues[$property] ?? null);
    }

    if ($value === '' && str_starts_with($property, 'PROPERTY_')) {
        $propertyId = substr($property, strlen('PROPERTY_'));
        $value = normalizePromptPropertyValue($propertyValues[$propertyId] ?? null);
    }

    return $value;
}

function normalizePromptPropertyValue($value): string
{
    if (is_array($value)) {
        if (array_key_exists('TEXT', $value)) {
            $value = $value['TEXT'];
        } elseif (array_key_exists('VALUE', $value)) {
            $value = $value['VALUE'];
        } else {
            $parts = [];
            foreach ($value as $item) {
                $text = normalizePromptPropertyValue($item);
                if ($text !== '') {
                    $parts[] = $text;
                }
            }

            return trim(implode("\n", $parts));
        }
    }

    return trim(html_entity_decode(strip_tags((string) $value), ENT_QUOTES | ENT_HTML5, 'UTF-8'));
}
