<?php
namespace GemAcc;

use PDO;
use Throwable;

/** Referral tracking + first-purchase reward service. */
final class ReferralService
{
    public static function ensureSchema(PDO $pdo): void
    {
        try {
            $pdo->exec("CREATE TABLE IF NOT EXISTS referral_rewards (id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, referrer_id BIGINT NOT NULL, referred_user_id BIGINT NOT NULL, order_id BIGINT UNSIGNED NOT NULL, amount INT NOT NULL DEFAULT 0, status VARCHAR(30) NOT NULL DEFAULT 'COMPLETED', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id), UNIQUE KEY uniq_referred_first_order (referred_user_id), KEY idx_referrer_created (referrer_id, created_at), KEY idx_order (order_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
            $pdo->exec("CREATE TABLE IF NOT EXISTS referral_events (id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT NOT NULL, referrer_id BIGINT NULL, event_type VARCHAR(50) NOT NULL, meta_json LONGTEXT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id), KEY idx_user_created (user_id, created_at), KEY idx_referrer_created (referrer_id, created_at)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
        } catch (Throwable $e) {
            error_log('[ReferralService] ensureSchema failed: ' . $e->getMessage());
        }
    }

    public static function captureStartPayload(PDO $pdo, int $userId, string $text): ?int
    {
        self::ensureSchema($pdo);
        if ($userId <= 0) return null;
        $text = trim($text);
        if (!preg_match('/^\/start\s+ref[_-]?(\d{4,20})$/i', $text, $m)) return null;
        $referrerId = (int)$m[1];
        if ($referrerId <= 0 || $referrerId === $userId) {
            self::logEvent($pdo, $userId, $referrerId, 'rejected_self_or_invalid');
            return null;
        }
        try {
            $pdo->beginTransaction();
            $st = $pdo->prepare("SELECT id, referrer_id FROM users WHERE id=? FOR UPDATE");
            $st->execute([$userId]);
            $user = $st->fetch(PDO::FETCH_ASSOC);
            if (!$user) {
                $pdo->prepare("INSERT INTO users(id, referrer_id) VALUES(?, ?)")->execute([$userId, $referrerId]);
            } elseif (!empty($user['referrer_id'])) {
                $pdo->commit();
                self::logEvent($pdo, $userId, $referrerId, 'ignored_existing_referrer');
                return (int)$user['referrer_id'];
            } else {
                $refExists = $pdo->prepare("SELECT id FROM users WHERE id=? LIMIT 1");
                $refExists->execute([$referrerId]);
                if (!$refExists->fetchColumn()) {
                    $pdo->commit();
                    self::logEvent($pdo, $userId, $referrerId, 'rejected_referrer_not_found');
                    return null;
                }
                $orders = $pdo->prepare("SELECT COUNT(*) FROM orders WHERE user_id=? AND status IN ('DELIVERED','APPROVED','PAID')");
                $orders->execute([$userId]);
                if ((int)$orders->fetchColumn() > 0) {
                    $pdo->commit();
                    self::logEvent($pdo, $userId, $referrerId, 'rejected_existing_customer');
                    return null;
                }
                $pdo->prepare("UPDATE users SET referrer_id=? WHERE id=? AND (referrer_id IS NULL OR referrer_id=0)")->execute([$referrerId, $userId]);
            }
            $pdo->commit();
            self::logEvent($pdo, $userId, $referrerId, 'captured');
            return $referrerId;
        } catch (Throwable $e) {
            if ($pdo->inTransaction()) $pdo->rollBack();
            error_log('[ReferralService] capture failed: ' . $e->getMessage());
            return null;
        }
    }

    public static function rewardFirstPurchase(PDO $pdo, int $userId, int $orderId, int $purchaseAmount = 0): array
    {
        self::ensureSchema($pdo);
        if ($userId <= 0 || $orderId <= 0) return ['ok'=>false,'reason'=>'invalid'];
        try {
            $pdo->beginTransaction();
            $u = $pdo->prepare("SELECT referrer_id FROM users WHERE id=? FOR UPDATE");
            $u->execute([$userId]);
            $referrerId = (int)$u->fetchColumn();
            if ($referrerId <= 0 || $referrerId === $userId) { $pdo->commit(); return ['ok'=>false,'reason'=>'no_referrer']; }
            $check = $pdo->prepare("SELECT id FROM referral_rewards WHERE referred_user_id=? LIMIT 1 FOR UPDATE");
            $check->execute([$userId]);
            if ($check->fetchColumn()) { $pdo->commit(); return ['ok'=>false,'reason'=>'already_rewarded']; }
            $validOrders = $pdo->prepare("SELECT COUNT(*) FROM orders WHERE user_id=? AND status IN ('DELIVERED','APPROVED','PAID')");
            $validOrders->execute([$userId]);
            if ((int)$validOrders->fetchColumn() !== 1) { $pdo->commit(); return ['ok'=>false,'reason'=>'not_first_purchase']; }
            $amount = self::rewardAmount($pdo, $purchaseAmount);
            $pdo->prepare("INSERT INTO referral_rewards(referrer_id, referred_user_id, order_id, amount) VALUES(?,?,?,?)")->execute([$referrerId, $userId, $orderId, $amount]);
            if ($amount > 0) {
                $pdo->prepare("UPDATE users SET balance=balance+? WHERE id=?")->execute([$amount, $referrerId]);
                $pdo->prepare("INSERT INTO wallet_transactions(user_id, amount, type, status, description) VALUES(?, ?, 'REFERRAL', 'COMPLETED', ?)")->execute([$referrerId, $amount, 'پاداش معرفی کاربر #' . $userId . ' برای سفارش #' . $orderId]);
            }
            $pdo->commit();
            self::logEvent($pdo, $userId, $referrerId, 'rewarded', ['order_id'=>$orderId,'amount'=>$amount]);
            return ['ok'=>true,'referrer_id'=>$referrerId,'amount'=>$amount];
        } catch (Throwable $e) {
            if ($pdo->inTransaction()) $pdo->rollBack();
            error_log('[ReferralService] reward failed: ' . $e->getMessage());
            return ['ok'=>false,'reason'=>'exception','error'=>$e->getMessage()];
        }
    }

    private static function rewardAmount(PDO $pdo, int $purchaseAmount): int
    {
        try {
            $st = $pdo->prepare("SELECT value FROM settings WHERE key_name='referral_first_purchase_reward' LIMIT 1");
            $st->execute();
            $v = trim((string)$st->fetchColumn());
            if ($v !== '') return max(0, (int)preg_replace('/\D+/', '', $v));
        } catch (Throwable $ignored) {}
        return 0;
    }

    private static function logEvent(PDO $pdo, int $userId, ?int $referrerId, string $type, array $meta = []): void
    {
        try {
            $pdo->prepare("INSERT INTO referral_events(user_id, referrer_id, event_type, meta_json) VALUES(?,?,?,?)")->execute([$userId, $referrerId, $type, json_encode($meta, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)]);
        } catch (Throwable $ignored) {}
    }
}
