<?php
namespace EasyChat\Library\Catalog;






class CmsCatalogConnectionResolver {

    private const SUPPORTED_TYPES = array('opencart', 'wordpress', 'bitrix', 'webasyst');

    public static function resolve($db, array $settings, string $edition = ''): array {
        $stored_type = self::normalizeType($settings['chat_cms_type'] ?? 'none');
        $stored_prefix = self::normalizePrefix($settings['chat_cms_prefix'] ?? '');

        if ($stored_type !== 'none') {
            $capability = CmsCatalogCapability::inspect($db, $stored_type, $stored_prefix);
            if (!empty($capability['ready'])) {
                return self::result(true, $stored_type, $stored_prefix, 'stored', false);
            }
        }

        $preferred_type = $stored_type !== 'none' ? $stored_type : self::typeForEdition($edition);
        $tables = self::tableNames($db);
        if ($tables === null) {
            return self::result(false, $preferred_type, $stored_prefix, 'schema_unavailable', false);
        }

        $candidates = self::candidates($tables, $preferred_type);
        $matches = array();
        foreach ($candidates as $candidate) {
            $capability = CmsCatalogCapability::inspect($db, $candidate['type'], $candidate['prefix']);
            if (!empty($capability['ready'])) {
                $matches[$candidate['type'] . "\0" . $candidate['prefix']] = $candidate;
            }
        }

        if (count($matches) !== 1) {
            return self::result(false, $preferred_type, $stored_prefix, count($matches) > 1 ? 'ambiguous' : 'not_found', count($matches) > 1);
        }

        $match = reset($matches);
        return self::result(true, $match['type'], $match['prefix'], 'schema_detected', false);
    }

    private static function candidates(array $tables, string $preferred_type): array {
        $signatures = array(
            'opencart' => 'product_description',
            'wordpress' => 'posts',
            'bitrix' => 'iblock_element',
            'webasyst' => 'shop_product',
        );
        $types = $preferred_type !== 'none' ? array($preferred_type) : self::SUPPORTED_TYPES;
        $result = array();
        foreach ($types as $type) {
            $suffix = $signatures[$type];
            foreach ($tables as $table) {
                if (strlen($table) < strlen($suffix) || substr($table, -strlen($suffix)) !== $suffix) {
                    continue;
                }
                $prefix = substr($table, 0, strlen($table) - strlen($suffix));
                if (preg_match('/^[A-Za-z0-9_]*$/', $prefix)) {
                    $result[$type . "\0" . $prefix] = array('type' => $type, 'prefix' => $prefix);
                }
            }
        }
        return array_values($result);
    }

    private static function tableNames($db): ?array {
        try {
            $result = $db->query('SHOW TABLES');
            $tables = array();
            foreach (($result->rows ?? array()) as $row) {
                $name = reset($row);
                if (is_string($name) && preg_match('/^[A-Za-z0-9_]+$/', $name)) {
                    $tables[] = $name;
                }
            }
            return $tables;
        } catch (\Throwable $e) {
            return null;
        }
    }

    private static function typeForEdition(string $edition): string {
        $edition = strtolower(trim($edition));
        if (in_array($edition, array('wordpress', 'wordpress_org'), true)) {
            return 'wordpress';
        }
        if ($edition === 'webasyst_store') {
            return 'webasyst';
        }
        return in_array($edition, array('opencart', 'bitrix'), true) ? $edition : 'none';
    }

    private static function normalizeType($type): string {
        $type = strtolower(trim((string)$type));
        return in_array($type, self::SUPPORTED_TYPES, true) ? $type : 'none';
    }

    private static function normalizePrefix($prefix): string {
        $prefix = trim((string)$prefix);
        return preg_match('/^[A-Za-z0-9_]*$/', $prefix) ? $prefix : '';
    }

    private static function result(bool $ready, string $type, string $prefix, string $source, bool $ambiguous): array {
        return array(
            'ready' => $ready,
            'type' => $type,
            'prefix' => $prefix,
            'source' => $source,
            'ambiguous' => $ambiguous,
        );
    }
}
