<?php

namespace EasyChat\Library\Install;

use EasyChat\Library\CentralGatewayClient;
use EasyChat\Library\EasyTokensGiftProvisioner;








class InstallationAttributionReporter
{
    const CHALLENGE_TTL_SECONDS = 600;

    public static function reportWithModel($model_setting, array $params)
    {
        $getter = function ($key, $default = '') use ($model_setting) {
            return (string)$model_setting->get($key, $default);
        };
        $setter = function ($key, $value) use ($model_setting) {
            $model_setting->set($key, (string)$value);
        };
        return self::report($getter, $setter, $params);
    }

    public static function reportWithMysqli($conn, $prefix, array $params)
    {
        $getter = function ($key, $default = '') use ($conn, $prefix) {
            $stmt = $conn->prepare("SELECT `value` FROM `{$prefix}settings` WHERE `key`=? LIMIT 1");
            if (!$stmt) return (string)$default;
            $stmt->bind_param('s', $key);
            if (!$stmt->execute()) {
                $stmt->close();
                return (string)$default;
            }
            $stmt->bind_result($value);
            $found = $stmt->fetch();
            $stmt->close();
            return $found ? (string)$value : (string)$default;
        };
        $setter = function ($key, $value) use ($conn, $prefix) {
            $stmt = $conn->prepare(
                "INSERT INTO `{$prefix}settings` (`key`,`value`) VALUES (?,?) "
                . "ON DUPLICATE KEY UPDATE `value`=VALUES(`value`)"
            );
            if (!$stmt) return;
            $value = (string)$value;
            $stmt->bind_param('ss', $key, $value);
            $stmt->execute();
            $stmt->close();
        };
        return self::report($getter, $setter, $params);
    }

    private static function report($getter, $setter, array $params)
    {
        $code = self::normalizeCode(self::value($params, 'install_code', $getter('chat_marketing_install_code', '')));
        if ($code === '') {
            if (array_key_exists('install_code', $params)) {
                $setter('chat_marketing_install_code', '');
                $setter('chat_marketing_attribution_status', 'not_requested');
                $setter('chat_marketing_attribution_error', '');
            }
            return array('success' => true, 'status' => 'not_requested');
        }
        if (!self::truthy(self::value($params, 'easychat_services_consent', $getter('chat_easychat_services_consent', '0')))) {
            return array('success' => false, 'status' => 'consent_required', 'message' => 'Для проверки кода включите сервисы EasyChat24.');
        }

        $site_url = self::siteUrl(self::value($params, 'site_url', defined('HTTP_SERVER') ? HTTP_SERVER : ''));
        $domain = EasyTokensGiftProvisioner::publicDomain($site_url);
        if ($site_url === '' || $domain === '') {
            return self::storeResult($setter, $code, 'retryable', 'domain_invalid');
        }

        $install_id = trim($getter('chat_install_id', ''));
        $install_secret = trim($getter('chat_install_secret', ''));
        if ($install_id === '' || $install_secret === '') {
            return self::storeResult($setter, $code, 'retryable', 'installation_identity_missing');
        }
        $gateway = CentralGatewayClient::normalizeBaseUrl($getter('chat_central_api', ''));
        if ($gateway === '') {
            $gateway = EasyTokensGiftProvisioner::defaultGatewayApi();
        }

        $nonce = bin2hex(random_bytes(16));
         
         
        $setter('chat_easytokens_gift_challenge_nonce', $nonce);
        $setter('chat_easytokens_gift_challenge_expires', (string)(time() + self::CHALLENGE_TTL_SECONDS));
        $setter('chat_marketing_install_code', $code);
        $setter('chat_marketing_attribution_status', 'pending');
        $setter('chat_marketing_attribution_error', '');

        $payload = array(
            'product' => 'easychat',
            'domain' => $domain,
            'install_code' => $code,
            'cms' => self::value($params, 'cms', self::value($params, 'edition', '')),
            'edition' => self::value($params, 'edition', ''),
            'version' => self::value($params, 'version', defined('EASYCHAT_VERSION') ? EASYCHAT_VERSION : ''),
            'challenge_url' => rtrim($site_url, '/') . '/index.php?route=provisioning/challenge',
            'challenge_nonce' => $nonce,
        );
         
         
        $body = CentralGatewayClient::signedUnlicensedBody($install_secret, $install_id, $payload);
        $response = CentralGatewayClient::postJson(
            $gateway,
            '/api/v1/installations/marketing-link',
            $body,
            12,
            isset($params['registry']) && is_object($params['registry']) ? $params['registry'] : null
        );
        $decoded = is_array($response['json'] ?? null) ? $response['json'] : array();
        if ((int)($response['status'] ?? 0) === 200 && !empty($decoded['success'])) {
            $setter('chat_marketing_attribution_status', 'linked');
            $setter('chat_marketing_attribution_error', '');
            $setter('chat_marketing_attribution_linked_at', date('c'));
             
            $setter('chat_marketing_install_code', '');
            return array('success' => true, 'status' => 'linked');
        }

        $error = (string)($decoded['error'] ?? ($decoded['code'] ?? ($response['error_code'] ?? 'gateway_unreachable')));
        return self::storeResult($setter, $code, (int)($response['status'] ?? 0) >= 500 ? 'retryable' : 'invalid', $error);
    }

    private static function storeResult($setter, $code, $status, $error)
    {
        $setter('chat_marketing_install_code', (string)$code);
        $setter('chat_marketing_attribution_status', (string)$status);
        $setter('chat_marketing_attribution_error', substr((string)$error, 0, 96));
        return array('success' => false, 'status' => (string)$status, 'code' => (string)$error);
    }

    private static function normalizeCode($value)
    {
        $code = strtoupper((string)preg_replace('/[^A-Z0-9]/i', '', trim((string)$value)));
        if (strpos($code, 'EC') === 0) $code = substr($code, 2);
        if (!preg_match('/^[A-HJ-NP-Z2-9]{8}$/D', $code)) return '';
        return 'EC-' . substr($code, 0, 4) . '-' . substr($code, 4, 4);
    }

    private static function value(array $params, $key, $default = '')
    {
        return isset($params[$key]) && is_scalar($params[$key]) ? trim((string)$params[$key]) : trim((string)$default);
    }

    private static function truthy($value)
    {
        return in_array(strtolower(trim((string)$value)), array('1', 'true', 'yes', 'on'), true);
    }

    private static function siteUrl($value)
    {
        $parts = parse_url(trim((string)$value));
        if (!$parts || !in_array(strtolower((string)($parts['scheme'] ?? '')), array('http', 'https'), true) || empty($parts['host'])) {
            return '';
        }
        $port = isset($parts['port']) ? ':' . (int)$parts['port'] : '';
        $path = isset($parts['path']) ? rtrim((string)$parts['path'], '/') : '';
        return strtolower((string)$parts['scheme']) . '://' . strtolower((string)$parts['host']) . $port . $path . '/';
    }
}
