<?php

/**
 * Configurable referral / sub-affiliate rewards.
 */
class ReferralService
{
    private const SETTING_TYPE = 'REFERRAL_REWARDS';
    private const USER_META_PREFIX = 'REFERRAL_USER_META_';

    /** @return array<string, mixed> */
    public static function defaultSettings(): array
    {
        return [
            'enabled' => 'on',
            'joinDiscountPercent' => 10,
            'walletRewardPerPurchase' => 3000,
            'tiers' => [
                [
                    'minReferrals' => 3,
                    'requireAllPurchased' => false,
                    'permanentDiscountPercent' => 8,
                    'couponDiscountPercent' => 0,
                ],
                [
                    'minReferrals' => 3,
                    'requireAllPurchased' => true,
                    'permanentDiscountPercent' => 15,
                    'couponDiscountPercent' => 50,
                ],
            ],
        ];
    }

    /** @return array<string, mixed> */
    public static function getSettings(): array
    {
        global $connection;
        $defaults = self::defaultSettings();
        $stmt = $connection->prepare('SELECT `value` FROM `setting` WHERE `type` = ? LIMIT 1');
        $type = self::SETTING_TYPE;
        $stmt->bind_param('s', $type);
        $stmt->execute();
        $row = $stmt->get_result()->fetch_assoc();
        $stmt->close();
        if (!$row || $row['value'] === null || $row['value'] === '') {
            return $defaults;
        }
        $saved = json_decode((string) $row['value'], true);
        if (!is_array($saved)) {
            return $defaults;
        }
        $merged = array_merge($defaults, $saved);
        if (!empty($saved['tiers']) && is_array($saved['tiers'])) {
            $merged['tiers'] = $saved['tiers'];
        }
        return $merged;
    }

    /** @param array<string, mixed> $settings */
    public static function saveSettings(array $settings): void
    {
        global $connection;
        $payload = json_encode($settings, JSON_UNESCAPED_UNICODE);
        $type = self::SETTING_TYPE;
        $stmt = $connection->prepare('SELECT `id` FROM `setting` WHERE `type` = ? LIMIT 1');
        $stmt->bind_param('s', $type);
        $stmt->execute();
        $exists = $stmt->get_result()->num_rows > 0;
        $stmt->close();
        if ($exists) {
            $stmt = $connection->prepare('UPDATE `setting` SET `value` = ? WHERE `type` = ?');
            $stmt->bind_param('ss', $payload, $type);
        } else {
            $stmt = $connection->prepare('INSERT INTO `setting` (`value`, `type`) VALUES (?, ?)');
            $stmt->bind_param('ss', $payload, $type);
        }
        $stmt->execute();
        $stmt->close();
    }

    public static function isEnabled(): bool
    {
        $settings = self::getSettings();
        return ($settings['enabled'] ?? 'off') === 'on';
    }

    public static function buildInviteLink(int $userId): string
    {
        static $botUsername = null;
        if ($botUsername === null) {
            $me = bot('getMe');
            $botUsername = is_object($me->result ?? null)
                ? (string) ($me->result->username ?? '')
                : '';
        }
        return $botUsername !== '' ? 'https://t.me/' . $botUsername . '?start=' . $userId : '';
    }

    /** @return array{total:int,purchased:int} */
    public static function getReferralCounts(int $userId): array
    {
        global $connection;
        $stmt = $connection->prepare('SELECT COUNT(*) AS c FROM `users` WHERE `refered_by` = ?');
        $stmt->bind_param('i', $userId);
        $stmt->execute();
        $total = (int) ($stmt->get_result()->fetch_assoc()['c'] ?? 0);
        $stmt->close();

        $stmt = $connection->prepare(
            'SELECT COUNT(DISTINCT u.`userid`) AS c
             FROM `users` u
             INNER JOIN `orders_list` o ON o.`userid` = u.`userid`
             WHERE u.`refered_by` = ?'
        );
        $stmt->bind_param('i', $userId);
        $stmt->execute();
        $purchased = (int) ($stmt->get_result()->fetch_assoc()['c'] ?? 0);
        $stmt->close();

        return ['total' => $total, 'purchased' => $purchased];
    }

    public static function getJoinDiscountPercent(int $userId): int
    {
        if (!self::isEnabled()) {
            return 0;
        }
        global $connection;
        $stmt = $connection->prepare('SELECT `refered_by` FROM `users` WHERE `userid` = ? LIMIT 1');
        $stmt->bind_param('i', $userId);
        $stmt->execute();
        $row = $stmt->get_result()->fetch_assoc();
        $stmt->close();
        if (empty($row['refered_by'])) {
            return 0;
        }
        return max(0, (int) (self::getSettings()['joinDiscountPercent'] ?? 0));
    }

    public static function getPermanentDiscountPercent(int $userId): int
    {
        if (!self::isEnabled()) {
            return 0;
        }
        $counts = self::getReferralCounts($userId);
        $best = 0;
        foreach (self::getSettings()['tiers'] ?? [] as $tier) {
            if (!is_array($tier)) {
                continue;
            }
            $minReferrals = max(0, (int) ($tier['minReferrals'] ?? 0));
            $requireAllPurchased = !empty($tier['requireAllPurchased']);
            $referralCount = $requireAllPurchased ? $counts['purchased'] : $counts['total'];
            if ($referralCount < $minReferrals) {
                continue;
            }
            $best = max($best, max(0, (int) ($tier['permanentDiscountPercent'] ?? 0)));
        }
        return $best;
    }

    public static function getBestAutomaticDiscountPercent(int $userId): int
    {
        return max(self::getJoinDiscountPercent($userId), self::getPermanentDiscountPercent($userId));
    }

    public static function applyDiscountToPrice(int $price, int $userId): int
    {
        $discount = self::getBestAutomaticDiscountPercent($userId);
        if ($discount <= 0 || $price <= 0) {
            return $price;
        }
        $price -= (int) floor($price * $discount / 100);
        return max(0, $price);
    }

    /** @return array<string, mixed> */
    private static function getUserMeta(int $userId): array
    {
        global $connection;
        $type = self::USER_META_PREFIX . $userId;
        $stmt = $connection->prepare('SELECT `value` FROM `setting` WHERE `type` = ? LIMIT 1');
        $stmt->bind_param('s', $type);
        $stmt->execute();
        $row = $stmt->get_result()->fetch_assoc();
        $stmt->close();
        if (!$row || $row['value'] === null || $row['value'] === '') {
            return [];
        }
        $decoded = json_decode((string) $row['value'], true);
        return is_array($decoded) ? $decoded : [];
    }

    /** @param array<string, mixed> $meta */
    private static function setUserMeta(int $userId, array $meta): void
    {
        global $connection;
        $type = self::USER_META_PREFIX . $userId;
        $payload = json_encode($meta, JSON_UNESCAPED_UNICODE);
        $stmt = $connection->prepare('SELECT `id` FROM `setting` WHERE `type` = ? LIMIT 1');
        $stmt->bind_param('s', $type);
        $stmt->execute();
        $exists = $stmt->get_result()->num_rows > 0;
        $stmt->close();
        if ($exists) {
            $stmt = $connection->prepare('UPDATE `setting` SET `value` = ? WHERE `type` = ?');
            $stmt->bind_param('ss', $payload, $type);
        } else {
            $stmt = $connection->prepare('INSERT INTO `setting` (`value`, `type`) VALUES (?, ?)');
            $stmt->bind_param('ss', $payload, $type);
        }
        $stmt->execute();
        $stmt->close();
    }

    public static function grantCoupon(int $userId, int $percent): ?string
    {
        global $connection;
        if ($percent <= 0) {
            return null;
        }
        $hashId = RandomString();
        $type = 'percent';
        $expireDate = 0;
        $expireCount = 1;
        $canUse = 1;
        $stmt = $connection->prepare(
            'INSERT INTO `discounts` (`hash_id`, `type`, `amount`, `expire_date`, `expire_count`, `can_use`)
             VALUES (?, ?, ?, ?, ?, ?)'
        );
        $stmt->bind_param('ssiiii', $hashId, $type, $percent, $expireDate, $expireCount, $canUse);
        $stmt->execute();
        $stmt->close();
        sendMessage(
            "🎁 تبریک! کد تخفیف {$percent}٪ یک‌بار مصرف شما:\n\n<code>{$hashId}</code>\n\nدر مرحله پرداخت می‌توانید از آن استفاده کنید.",
            null,
            'HTML',
            $userId
        );
        return $hashId;
    }

    public static function onReferralPurchase(int $buyerId): void
    {
        if (!self::isEnabled()) {
            return;
        }
        global $connection;
        $stmt = $connection->prepare('SELECT `refered_by` FROM `users` WHERE `userid` = ? LIMIT 1');
        $stmt->bind_param('i', $buyerId);
        $stmt->execute();
        $buyer = $stmt->get_result()->fetch_assoc();
        $stmt->close();
        if (empty($buyer['refered_by'])) {
            return;
        }
        $inviterId = (int) $buyer['refered_by'];
        if ($inviterId <= 0) {
            return;
        }

        $settings = self::getSettings();
        $reward = max(0, (int) ($settings['walletRewardPerPurchase'] ?? 0));
        if ($reward > 0) {
            $stmt = $connection->prepare('UPDATE `users` SET `wallet` = `wallet` + ? WHERE `userid` = ?');
            $stmt->bind_param('ii', $reward, $inviterId);
            $stmt->execute();
            $stmt->close();
            sendMessage(
                'تبریک! یکی از زیرمجموعه‌های شما خرید انجام داد و مبلغ ' . number_format($reward) . ' تومان به کیف پول شما اضافه شد.',
                null,
                null,
                $inviterId
            );
        }

        self::evaluateInviterRewards($inviterId);
    }

    public static function evaluateInviterRewards(int $inviterId): void
    {
        if (!self::isEnabled()) {
            return;
        }
        $counts = self::getReferralCounts($inviterId);
        $meta = self::getUserMeta($inviterId);
        $notifiedTiers = $meta['notifiedTiers'] ?? [];
        if (!is_array($notifiedTiers)) {
            $notifiedTiers = [];
        }

        foreach (self::getSettings()['tiers'] ?? [] as $index => $tier) {
            if (!is_array($tier)) {
                continue;
            }
            $tierKey = (string) $index;
            $minReferrals = max(0, (int) ($tier['minReferrals'] ?? 0));
            $requireAllPurchased = !empty($tier['requireAllPurchased']);
            $referralCount = $requireAllPurchased ? $counts['purchased'] : $counts['total'];
            if ($referralCount < $minReferrals) {
                continue;
            }
            if (in_array($tierKey, $notifiedTiers, true)) {
                continue;
            }

            $permanent = max(0, (int) ($tier['permanentDiscountPercent'] ?? 0));
            $coupon = max(0, (int) ($tier['couponDiscountPercent'] ?? 0));
            $message = "🎉 پله زیرمجموعه‌گیری شما فعال شد!\n";
            if ($permanent > 0) {
                $message .= "• تخفیف دائمی {$permanent}٪ روی خریدهای بعدی\n";
            }
            if ($coupon > 0 && empty($meta['couponTier_' . $tierKey])) {
                self::grantCoupon($inviterId, $coupon);
                $meta['couponTier_' . $tierKey] = 1;
            }
            sendMessage(trim($message), null, null, $inviterId);
            $notifiedTiers[] = $tierKey;
        }

        $meta['notifiedTiers'] = array_values(array_unique($notifiedTiers));
        self::setUserMeta($inviterId, $meta);
    }

    public static function formatUserStats(int $userId): string
    {
        return self::formatInviterPanel($userId);
    }

    public static function formatInviterPanel(int $userId): string
    {
        $counts = self::getReferralCounts($userId);
        $permanent = self::getPermanentDiscountPercent($userId);
        $lines = [
            "📊 آمار شما:",
            "👥 تعداد زیرمجموعه: {$counts['total']}",
            "🛒 زیرمجموعه با خرید موفق: {$counts['purchased']}",
        ];
        if ($permanent > 0) {
            $lines[] = "⭐ تخفیف دائمی فعال: {$permanent}٪";
        }
        return implode("\n", $lines);
    }

    public static function formatProgramRules(): string
    {
        $settings = self::getSettings();
        $lines = ['🎁 مزایای برنامه:'];
        $joinDiscount = max(0, (int) ($settings['joinDiscountPercent'] ?? 0));
        if ($joinDiscount > 0) {
            $lines[] = "• کاربر دعوت‌شده {$joinDiscount}٪ تخفیف روی خرید دارد";
        }
        $walletReward = max(0, (int) ($settings['walletRewardPerPurchase'] ?? 0));
        if ($walletReward > 0) {
            $lines[] = '• هر خرید موفق زیرمجموعه = ' . number_format($walletReward) . ' تومان پاداش کیف پول';
        }
        foreach ($settings['tiers'] ?? [] as $index => $tier) {
            if (!is_array($tier)) {
                continue;
            }
            $minReferrals = max(0, (int) ($tier['minReferrals'] ?? 0));
            if ($minReferrals <= 0) {
                continue;
            }
            $requirePurchased = !empty($tier['requireAllPurchased']);
            $referralLabel = $requirePurchased ? 'زیرمجموعه با خرید موفق' : 'زیرمجموعه';
            $benefits = [];
            $permanent = max(0, (int) ($tier['permanentDiscountPercent'] ?? 0));
            $coupon = max(0, (int) ($tier['couponDiscountPercent'] ?? 0));
            if ($permanent > 0) {
                $benefits[] = "تخفیف دائمی {$permanent}٪";
            }
            if ($coupon > 0) {
                $benefits[] = "کد تخفیف {$coupon}٪";
            }
            if ($benefits !== []) {
                $lines[] = '• پله ' . ($index + 1) . " ({$minReferrals} {$referralLabel}): " . implode(' + ', $benefits);
            }
        }
        return implode("\n", $lines);
    }

    /** @return array{text:string,keyboard:string,link:string} */
    public static function getUserInvitePayload(int $userId): array
    {
        global $buttonValues;
        $link = self::buildInviteLink($userId);
        $text = implode("\n\n", array_filter([
            '👥 <b>زیرمجموعه‌گیری</b>',
            "🔗 لینک اختصاصی شما:\n<code>{$link}</code>",
            self::formatInviterPanel($userId),
            self::formatProgramRules(),
            'این لینک را برای دوستانتان بفرستید تا با عضویت و خرید، پاداش بگیرید.',
        ]));
        $keyboard = json_encode(['inline_keyboard' => [
            [['text' => $buttonValues['back_to_main'], 'callback_data' => 'mainMenu']],
        ]]);
        return ['text' => $text, 'keyboard' => $keyboard, 'link' => $link];
    }

    public static function getAdminMenuKeyboard(): string
    {
        global $buttonValues;
        $settings = self::getSettings();
        $enabled = ($settings['enabled'] ?? 'off') === 'on' ? $buttonValues['on'] : $buttonValues['off'];
        return json_encode(['inline_keyboard' => [
            [['text' => 'وضعیت: ' . $enabled, 'callback_data' => 'toggleReferralEnabled']],
            [
                ['text' => (string) ($settings['joinDiscountPercent'] ?? 0) . '٪', 'callback_data' => 'editReferralJoinDiscount'],
                ['text' => 'تخفیف عضویت', 'callback_data' => 'wizwizch'],
            ],
            [
                ['text' => number_format((int) ($settings['walletRewardPerPurchase'] ?? 0)), 'callback_data' => 'editReferralWalletReward'],
                ['text' => 'پاداش خرید زیرمجموعه', 'callback_data' => 'wizwizch'],
            ],
            [['text' => '⚙️ پله‌های پاداش', 'callback_data' => 'referralTierList']],
            [['text' => $buttonValues['back_button'], 'callback_data' => 'botSettings']],
        ]]);
    }

    public static function getTierListKeyboard(): string
    {
        global $buttonValues;
        $settings = self::getSettings();
        $rows = [];
        foreach ($settings['tiers'] ?? [] as $index => $tier) {
            if (!is_array($tier)) {
                continue;
            }
            $min = (int) ($tier['minReferrals'] ?? 0);
            $perm = (int) ($tier['permanentDiscountPercent'] ?? 0);
            $coupon = (int) ($tier['couponDiscountPercent'] ?? 0);
            $allPurchased = !empty($tier['requireAllPurchased']) ? 'خریددار' : 'عضو';
            $label = 'پله ' . ($index + 1) . ": {$min} {$allPurchased} → {$perm}٪";
            if ($coupon > 0) {
                $label .= " + کد {$coupon}٪";
            }
            $rows[] = [['text' => $label, 'callback_data' => 'referralTierEdit' . $index]];
        }
        $rows[] = [['text' => '➕ افزودن پله', 'callback_data' => 'referralTierAdd']];
        $rows[] = [['text' => $buttonValues['back_button'], 'callback_data' => 'referralRewardSettings']];
        return json_encode(['inline_keyboard' => $rows]);
    }

    /** @return array<string, mixed> */
    public static function getTier(int $index): array
    {
        $tiers = self::getSettings()['tiers'] ?? [];
        return is_array($tiers[$index] ?? null) ? $tiers[$index] : [];
    }

    /** @param array<string, mixed> $tier */
    public static function saveTier(int $index, array $tier): void
    {
        $settings = self::getSettings();
        $tiers = $settings['tiers'] ?? [];
        $tiers[$index] = $tier;
        $settings['tiers'] = array_values($tiers);
        self::saveSettings($settings);
    }

    public static function addTier(): void
    {
        $settings = self::getSettings();
        $tiers = $settings['tiers'] ?? [];
        $tiers[] = [
            'minReferrals' => 3,
            'requireAllPurchased' => false,
            'permanentDiscountPercent' => 5,
            'couponDiscountPercent' => 0,
        ];
        $settings['tiers'] = $tiers;
        self::saveSettings($settings);
    }
}

function applyReferralDiscountToPrice(int $price, $userId): int
{
    if (!class_exists('ReferralService')) {
        return $price;
    }
    return ReferralService::applyDiscountToPrice($price, (int) $userId);
}

function userHasUnapprovedPurchase(int $userId): bool
{
    global $connection;
    $stmt = $connection->prepare(
        "SELECT COUNT(*) AS c FROM `pays`
         WHERE `user_id` = ? AND `state` NOT IN ('approved', 'declined', 'canceled')"
    );
    $stmt->bind_param('i', $userId);
    $stmt->execute();
    $count = (int) ($stmt->get_result()->fetch_assoc()['c'] ?? 0);
    $stmt->close();
    return $count > 0;
}
