<?php

require_once __DIR__ . '/../config/database.php';

class SystemConfigService
{
    public static function getActiveSymbols($coreOnly = false, $userId = null)
    {
        $orderSql = "
            ORDER BY
                CASE UPPER(COALESCE(s.asset_type, ''))
                    WHEN 'FOREX' THEN 1
                    WHEN 'METAL' THEN 2
                    WHEN 'METALS' THEN 2
                    WHEN 'INDEX' THEN 3
                    WHEN 'INDICES' THEN 3
                    WHEN 'CRYPTO' THEN 4
                    WHEN 'STOCK' THEN 5
                    WHEN 'STOCKS' THEN 5
                    ELSE 99
                END ASC,
                COALESCE(s.sort_order, 999999) ASC,
                s.symbol ASC
        ";

        if ($userId) {
            $stmt = db()->prepare("
                SELECT s.*
                FROM symbols s
                JOIN user_symbols us ON us.symbol_id = s.id
                WHERE s.is_active = 1
                  AND us.user_id = ?
                $orderSql
            ");
            $stmt->execute([$userId]);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        }

        if ($coreOnly) {
            $stmt = db()->query("
                SELECT s.*
                FROM symbols s
                WHERE s.is_active = 1
                  AND s.is_core = 1
                $orderSql
            ");
        } else {
            $stmt = db()->query("
                SELECT s.*
                FROM symbols s
                WHERE s.is_active = 1
                $orderSql
            ");
        }

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public static function getGroupedActiveSymbols($coreOnly = false, $userId = null)
    {
        $symbols = self::getActiveSymbols($coreOnly, $userId);
        $groups = [];

        foreach ($symbols as $symbol) {
            $assetType = strtoupper(trim((string)($symbol['asset_type'] ?? 'OTHER')));
            if ($assetType === '') {
                $assetType = 'OTHER';
            }
            $groups[$assetType][] = $symbol;
        }

        return $groups;
    }

    public static function getActiveAssetTypes($coreOnly = false, $userId = null)
    {
        return array_keys(self::getGroupedActiveSymbols($coreOnly, $userId));
    }

    public static function getTimeframes()
    {
        $stmt = db()->query("
            SELECT *
            FROM timeframes
            WHERE is_active = 1
            ORDER BY
                CASE
                    WHEN UPPER(code) IN ('1M', 'M1') THEN 1
                    WHEN UPPER(code) IN ('2M', 'M2') THEN 2
                    WHEN UPPER(code) IN ('3M', 'M3') THEN 3
                    WHEN UPPER(code) IN ('5M', 'M5') THEN 5
                    WHEN UPPER(code) IN ('10M', 'M10') THEN 10
                    WHEN UPPER(code) IN ('15M', 'M15') THEN 15
                    WHEN UPPER(code) IN ('30M', 'M30') THEN 30
                    WHEN UPPER(code) IN ('1H', 'H1') THEN 60
                    WHEN UPPER(code) IN ('2H', 'H2') THEN 120
                    WHEN UPPER(code) IN ('3H', 'H3') THEN 180
                    WHEN UPPER(code) IN ('4H', 'H4') THEN 240
                    WHEN UPPER(code) IN ('6H', 'H6') THEN 360
                    WHEN UPPER(code) IN ('8H', 'H8') THEN 480
                    WHEN UPPER(code) IN ('12H', 'H12') THEN 720
                    WHEN UPPER(code) IN ('1D', 'D1') THEN 1440
                    WHEN UPPER(code) IN ('1W', 'W1') THEN 10080
                    WHEN UPPER(code) IN ('MN', '1MN', 'MO', '1MO', 'MONTH', '1MONTH') THEN 43200
                    ELSE 999999
                END ASC,
                id ASC
        ");

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public static function getApiKey($provider = 'twelvedata')
    {
        $stmt = db()->prepare("
            SELECT api_key
            FROM api_settings
            WHERE LOWER(provider) = LOWER(?)
              AND is_active = 1
            LIMIT 1
        ");
        $stmt->execute([$provider]);
        return $stmt->fetchColumn();
    }

    public static function getApiInterval($timeframeCode)
    {
        $stmt = db()->prepare("
            SELECT api_interval
            FROM timeframes
            WHERE UPPER(code) = UPPER(?)
            LIMIT 1
        ");
        $stmt->execute([$timeframeCode]);
        return $stmt->fetchColumn();
    }

    public static function getSymbolConfig($symbol)
    {
        $symbol = strtoupper(str_replace(['/', '-', '_', ' '], '', trim((string)$symbol)));
        if ($symbol === '') {
            return self::symbolDefaults('');
        }

        try {
            $stmt = db()->prepare("SELECT * FROM symbols WHERE UPPER(REPLACE(REPLACE(REPLACE(REPLACE(symbol, '/', ''), '-', ''), '_', ''), ' ', '')) = ? LIMIT 1");
            $stmt->execute([$symbol]);
            $row = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
            return self::mergeSymbolDefaults($symbol, $row);
        } catch (Throwable $e) {
            return self::symbolDefaults($symbol);
        }
    }

    public static function getProviderSymbol($symbol, $provider = 'twelvedata')
    {
        $config = self::getSymbolConfig($symbol);
        $providerSymbol = trim((string)($config['provider_symbol'] ?? ''));

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

        return self::defaultProviderSymbol((string)($config['symbol'] ?? $symbol), (string)($config['asset_type'] ?? ''), $provider);
    }

    public static function getPriceDecimals($symbol)
    {
        $config = self::getSymbolConfig($symbol);
        return (int)($config['decimals'] ?? 2);
    }

    public static function getPipSize($symbol)
    {
        $config = self::getSymbolConfig($symbol);
        return (float)($config['pip_size'] ?? 0.0001);
    }

    public static function getPointSize($symbol)
    {
        $config = self::getSymbolConfig($symbol);
        return (float)($config['point_size'] ?? ($config['pip_size'] ?? 0.0001));
    }

    public static function getContractSize($symbol)
    {
        $config = self::getSymbolConfig($symbol);
        return (float)($config['contract_size'] ?? 100000);
    }

    public static function getLotStep($symbol)
    {
        $config = self::getSymbolConfig($symbol);
        return (float)($config['lot_step'] ?? 0.01);
    }

    public static function getMinLot($symbol)
    {
        $config = self::getSymbolConfig($symbol);
        return (float)($config['min_lot'] ?? 0.01);
    }

    public static function getNewsCurrencies($symbol)
    {
        $config = self::getSymbolConfig($symbol);
        $news = trim((string)($config['news_currency'] ?? ''));

        if ($news !== '') {
            return array_values(array_filter(array_map('trim', explode(',', strtoupper($news)))));
        }

        $base = strtoupper((string)($config['base_currency'] ?? ''));
        $quote = strtoupper((string)($config['quote_currency'] ?? ''));

        return array_values(array_filter(array_unique([$base, $quote])));
    }

    public static function defaultProviderSymbol($symbol, $assetType = '', $provider = 'twelvedata')
    {
        $symbol = strtoupper(str_replace(['/', '-', '_', ' '], '', trim((string)$symbol)));
        $assetType = strtoupper(trim((string)$assetType));

        if ($symbol === '') {
            return '';
        }

        if ($assetType === 'FOREX' || preg_match('/^[A-Z]{6}$/', $symbol)) {
            return substr($symbol, 0, 3) . '/' . substr($symbol, 3, 3);
        }

        if (in_array($assetType, ['METAL', 'METALS'], true) && strlen($symbol) >= 6) {
            return substr($symbol, 0, 3) . '/' . substr($symbol, 3, 3);
        }

        if ($assetType === 'CRYPTO' && strlen($symbol) >= 6) {
            $quote = substr($symbol, -3);
            $base = substr($symbol, 0, -3);
            return $base . '/' . $quote;
        }

        /*
         * Indices are provider-specific. For NAS100, US30, SPX500, GER40, etc.,
         * always set provider_symbol in Admin based on the provider's exact code.
         */
        return $symbol;
    }

    private static function mergeSymbolDefaults($symbol, array $row)
    {
        $defaults = self::symbolDefaults($symbol, (string)($row['asset_type'] ?? ''));

        foreach ($defaults as $key => $value) {
            if (!array_key_exists($key, $row) || $row[$key] === null || $row[$key] === '') {
                $row[$key] = $value;
            }
        }

        return $row;
    }

    private static function symbolDefaults($symbol, $assetType = '')
    {
        $symbol = strtoupper(str_replace(['/', '-', '_', ' '], '', trim((string)$symbol)));
        $assetType = strtoupper(trim((string)$assetType));

        if ($assetType === '') {
            if (preg_match('/^[A-Z]{6}$/', $symbol)) {
                $assetType = in_array(substr($symbol, 0, 3), ['XAU', 'XAG'], true) ? 'METAL' : 'FOREX';
            } elseif (preg_match('/(BTC|ETH|SOL|BNB|XRP|ADA|DOGE|LTC|BCH)/', $symbol)) {
                $assetType = 'CRYPTO';
            } elseif ($symbol !== '') {
                $assetType = 'INDEX';
            } else {
                $assetType = 'OTHER';
            }
        }

        $base = '';
        $quote = 'USD';

        if (preg_match('/^[A-Z]{6}$/', $symbol)) {
            $base = substr($symbol, 0, 3);
            $quote = substr($symbol, 3, 3);
        } elseif (substr($symbol, -3) === 'USD') {
            $base = substr($symbol, 0, -3);
            $quote = 'USD';
        } else {
            $base = $symbol;
        }

        $decimals = 2;
        $pipSize = 0.01;
        $pointSize = 0.01;
        $contractSize = 1;
        $tickSize = 0.01;
        $tickValue = 1;
        $minLot = 0.01;
        $lotStep = 0.01;

        if ($assetType === 'FOREX') {
            $decimals = ($quote === 'JPY') ? 3 : 5;
            $pipSize = ($quote === 'JPY') ? 0.01 : 0.0001;
            $pointSize = ($quote === 'JPY') ? 0.001 : 0.00001;
            $tickSize = $pointSize;
            $contractSize = 100000;
        } elseif (in_array($assetType, ['METAL', 'METALS'], true)) {
            if ($symbol === 'XAUUSD') {
                $decimals = 2;
                $pipSize = 0.1;
                $pointSize = 0.01;
                $tickSize = 0.01;
                $contractSize = 100;
            } elseif ($symbol === 'XAGUSD') {
                $decimals = 3;
                $pipSize = 0.01;
                $pointSize = 0.001;
                $tickSize = 0.001;
                $contractSize = 5000;
            }
        } elseif ($assetType === 'CRYPTO') {
            $decimals = 2;
            $pipSize = 1;
            $pointSize = 0.01;
            $tickSize = 0.01;
            $contractSize = 1;
        } elseif (in_array($assetType, ['INDEX', 'INDICES'], true)) {
            $decimals = 2;
            $pipSize = 1;
            $pointSize = 1;
            $tickSize = 1;
            $contractSize = 1;
        }

        return [
            'symbol' => $symbol,
            'asset_type' => $assetType,
            'provider' => 'twelvedata',
            'provider_symbol' => self::defaultProviderSymbol($symbol, $assetType, 'twelvedata'),
            'base_currency' => $base,
            'quote_currency' => $quote,
            'news_currency' => self::defaultNewsCurrency($symbol, $assetType, $base, $quote),
            'decimals' => $decimals,
            'pip_size' => $pipSize,
            'point_size' => $pointSize,
            'tick_size' => $tickSize,
            'tick_value' => $tickValue,
            'contract_size' => $contractSize,
            'min_lot' => $minLot,
            'lot_step' => $lotStep,
        ];
    }

    private static function defaultNewsCurrency($symbol, $assetType, $base, $quote)
    {
        $symbol = strtoupper((string)$symbol);
        $assetType = strtoupper((string)$assetType);

        if (in_array($assetType, ['METAL', 'METALS', 'CRYPTO', 'INDEX', 'INDICES'], true)) {
            return 'USD';
        }

        $items = array_values(array_filter(array_unique([strtoupper($base), strtoupper($quote)])));
        return implode(',', $items);
    }
}
