File size: 11,817 Bytes
e14bacb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
const router = require('express').Router();
const User = require('../models/User');
const Transaction = require('../models/Transaction');
const Asset = require('../models/Asset');
const verify = require('../utils/verifyToken');
const { generateKUS } = require('../utils/kusGenerator');
const StrikeHistory = require('../models/StrikeHistory');

const AllTransaction = require('../models/AllTransaction');
const logTransaction = require('../utils/ledgerLogger');
const { sendToUser } = require('../utils/sendPush');
const { runStrike } = require('../services/strikeEngine');

// MIDDLEWARE: Check if Admin
const verifyAdmin = async (req, res, next) => {
  const user = await User.findById(req.user._id);
  if (user.role !== 'admin') return res.status(403).send("ACCESS DENIED");
  next();
};

// 1. DASHBOARD STATS (The Top Grid)
router.get('/stats', verify, verifyAdmin, async (req, res) => {
  try {
    const today = new Date();
    today.setHours(0,0,0,0);

    // Calculate Today's Sales
    const dailySales = await Transaction.aggregate([
      { $match: { timestamp: { $gte: today }, status: 'Verified' } },
      { $group: { _id: null, total: { $sum: "$amount" } } }
    ]);

    const pendingCount = await Transaction.countDocuments({ status: 'Pending' });
    const userCount = await User.countDocuments();
    const bannedCount = await User.countDocuments({ ban_strikes: { $gte: 3 } });

    res.json({
      sales: dailySales[0]?.total || 0,
      pending: pendingCount,
      users: userCount,
      banned: bannedCount
    });
  } catch (err) {
    res.status(500).send("Stats Error");
  }
});

// 2. GET PENDING TRANSACTIONS (The Worklist)
router.get('/transactions/pending', verify, verifyAdmin, async (req, res) => {
  try {
    // Populate user name to see who is paying
    const txs = await Transaction.find({ status: 'Pending' })
      .populate('user_id', 'name email ban_strikes')
      .sort({ timestamp: -1 });
    res.json(txs);
  } catch (err) {
    res.status(500).send("Fetch Error");
  }
});

// 3. ACTION: APPROVE PAYMENT (Manual Verification)
router.post('/approve', verify, verifyAdmin, async (req, res) => {
  try {
    const { transactionId } = req.body;
    const tx = await Transaction.findById(transactionId);
    if (!tx || tx.status !== 'Pending') return res.status(400).send("Invalid Transaction");

    // 1. Generate Asset
    const newKUS = await generateKUS(tx.tier);

    // 3. Update Tx
    tx.status = 'Verified';
    await tx.save();

    await Asset.findByIdAndUpdate(tx.asset_id, { status: 'Held' });

    await logTransaction(tx.user_id, 'DEPOSIT', tx.amount, 'INR', `Deposit Verified (Tier: ${tx.tier})`);

    // 4. Referral Logic (Simplified)
    const assetCount = await Asset.countDocuments({ owner_id: tx.user_id });
    if (assetCount === 1) {
        const user = await User.findById(tx.user_id);
        if (user.referred_by) {
            const referrer = await User.findOne({ referral_code: user.referred_by });
            if (referrer) {
                let reward = 0;
                if (tx.tier === 'Silver') reward = 100;
                if (tx.tier === 'Gold') reward = 150;
                if (tx.tier === 'Platinum') reward = 250;

                let userReward = 0;
                if (tx.tier === 'Silver') reward = 50;
                if (tx.tier === 'Gold') reward = 75;
                if (tx.tier === 'Platinum') reward = 125;
                
                referrer.points += reward;
                await referrer.save();

                user.points += userReward;
                await user.save();

                await logTransaction(referrer._id, 'REFERRAL_BONUS', reward, 'INR', `Referral Bonus Tier: ${tx.tier}`);
                await sendToUser(referrer._id, "Referral Bonus Credited", `${reward} points credited to your account.`, "/profile");

                await logTransaction(user._id, 'REFERRAL_BONUS', userReward, 'INR', `Referral Bonus Tier: ${tx.tier}`);
                await sendToUser(user._id, "Referral Bonus Credited", `${userReward} points credited to your account.`, "/profile");

                console.log(`[Referral] ${reward} points added to ${referrer.name}`);
            }
        }
    }

    await sendToUser(tx.user_id, "✅ Deposit Verified", `₹${tx.amount} added to your assets.`, "/profile");

    res.json({ success: true, message: "Payment Verified & Asset Assigned" });
  } catch (err) {
    res.status(500).send("Approval Error");
  }
});

// 4. ACTION: REJECT & STRIKE (The Ban Hammer)
router.post('/reject', verify, verifyAdmin, async (req, res) => {
  try {
    const { transactionId } = req.body;
    const tx = await Transaction.findById(transactionId);
    if (!tx) return res.status(404).send("Tx not found");

    // 1. Mark Failed
    tx.status = 'Failed';
    tx.rejection_reason = "Invalid UTR / Payment Not Received"; // Static Reason
    await tx.save();

    await Asset.findByIdAndDelete(tx.asset_id);

    // 2. Add Strike to User
    const user = await User.findById(tx.user_id);
    user.ban_strikes += 1;
    await user.save();

    res.json({ 
      success: true, 
      message: `Transaction Rejected. User Strikes: ${user.ban_strikes}/3` 
    });
    await sendToUser(tx.user_id, "❌ Deposit Failed", "Your UTR was rejected. Check Activity Log.", "/profile");
  } catch (err) {
    res.status(500).send("Reject Error");
  }
});

module.exports = router;

// ADD STRIKE (Called when Admin rejects a UTR)
router.post('/strike-user', verify, verifyAdmin, async (req, res) => {
    const { userId } = req.body;
    
    const user = await User.findById(userId);
    user.ban_strikes += 1;
    await user.save();

    if (user.ban_strikes >= 3) {
        // Optional: Send email notification "You are banned"
        console.log(`User ${user.name} is now BANNED.`);
    }

    res.send({ message: `Strike added. Total: ${user.ban_strikes}/3` });
});

// 5. GET ALL USERS (Manage Users)
router.get('/users', verify, verifyAdmin, async (req, res) => {
    const users = await User.find().select('-password').sort({ createdAt: -1 });
    res.json(users);
});

// 6. GET ALL ASSETS (Asset Inventory)
router.get('/assets', verify, verifyAdmin, async (req, res) => {
    const assets = await Asset.find({ status: 'Held' }).populate('owner_id', 'name email');
    res.json(assets);
});

// 7. GET WINNER HISTORY (Last 60 Days)
router.get('/history', verify, verifyAdmin, async (req, res) => {
    const history = await StrikeHistory.find().sort({ date: -1 }).limit(60).populate('winners.user_id', 'name');
    res.json(history);
});

// 8. LEDGER (All Transactions)
router.get('/ledger', verify, verifyAdmin, async (req, res) => {
    const txs = await Transaction.find().populate('user_id', 'name').sort({ timestamp: -1 }).limit(100);
    res.json(txs);
});

// 9. MANUAL STRIKE TRIGGER
router.post('/trigger-strike', verify, verifyAdmin, async (req, res) => {
    // SECURITY: Ensure you export the logic function properly from jobs/strike.js
    // For now, let's assume you moved the logic to a controller function called `executeStrikeLogic`
    // await executeStrikeLogic(); 

    startStrike();
    res.json({ message: "Strike Triggered Manually" });
});

router.post('/manual-strike', verify, verifyAdmin, async (req, res) => {
  try {
    await runStrike({ triggeredBy: "ADMIN" });
    res.json({ success: true });
  } catch (err) {
    if (err.message === "STRIKE_ALREADY_EXECUTED") {
      return res.status(400).json("Strike already executed today");
    }
    res.status(500).json("Strike failed");
  }
});

// 10. UNBAN USER
router.post('/unban', verify, verifyAdmin, async (req, res) => {
    const { userId } = req.body;
    await User.findByIdAndUpdate(userId, { ban_strikes: 0 });
    res.json({ message: "User Unbanned" });
});

// WITHDRAWAL REQUESTS (Fixes 404)
router.get('/withdrawals', verify, verifyAdmin, async (req, res) => {
    const requests = await Transaction.find({ status: 'Pending_Withdrawal' })
        .populate('user_id', 'name email upi_id');
    res.json(requests);
});

// CONFIRM WITHDRAWAL PAID
router.post('/withdraw-confirm', verify, verifyAdmin, async (req, res) => {
    const { transactionId, adminUtr } = req.body;
    await Transaction.findByIdAndUpdate(transactionId, { 
        status: 'Withdrawn',
        utr: adminUtr 
    });
    await sendToUser(tx.user_id, "💸 Payment Sent", "Your withdrawal has been processed via UPI.", "/profile");
    res.json({ success: true });
});

router.get('/global-ledger', verify, verifyAdmin, async (req, res) => {
    try {
        // Support Filtering via Query Params
        const { type, email } = req.query;
        let query = {};

        if (type && type !== 'ALL') query.type = type;
        
        if (email) {
            const user = await User.findOne({ email });
            if (user) query.user_id = user._id;
        }

        const history = await AllTransaction.find(query)
            .populate('user_id', 'name email')
            .sort({ timestamp: -1 })
            .limit(200); // Limit to prevent crashing
            
        res.json(history);
    } catch (err) {
        res.status(500).send("Error");
    }
});

// REJECT WITHDRAWAL (Admin Action)
router.post('/withdraw-reject', verify, verifyAdmin, async (req, res) => {
    const { transactionId, reason } = req.body;
    
    const tx = await Transaction.findById(transactionId);
    if (!tx) return res.status(404).send("Tx Not Found");

    // 1. Refund the money to wallet
    const user = await User.findById(tx.user_id);
    user.wallet_balance += tx.amount;
    await user.save();

    // 2. Update Transaction
    tx.status = 'Rejected_Withdrawal';
    tx.rejection_reason = reason || "Admin Rejected Request";
    await tx.save();

    // 3. Log to Ledger (Refund)
    await logTransaction(user._id, 'REFUND', tx.amount, 'INR', `Withdrawal Rejected: ${reason}`);

    res.json({ success: true });
});

// 12. GET SINGLE USER DETAILS (Deep Dive)
router.get('/user/:id', verify, verifyAdmin, async (req, res) => {
    try {
        const user = await User.findById(req.params.id).select('-password');
        if (!user) return res.status(404).send("User not found");

        // Fetch their assets
        const assets = await Asset.find({ owner_id: user._id });
        
        // Fetch their transactions (Last 50)
        const txs = await Transaction.find({ user_id: user._id }).sort({ timestamp: -1 }).limit(50);

        res.json({ user, assets, transactions: txs });
    } catch (err) {
        res.status(500).send("Error fetching user details");
    }
});

// 13. UPDATE USER (Edit Details)
router.put('/user/:id', verify, verifyAdmin, async (req, res) => {
    try {
        const { name, email, wallet_balance, points, ban_strikes } = req.body;
        
        await User.findByIdAndUpdate(req.params.id, {
            name, 
            email, 
            wallet_balance, 
            points,
            ban_strikes
        });

        res.json({ success: true, message: "User Updated" });
    } catch (err) {
        res.status(500).send("Update Failed");
    }
});

// 14. DELETE USER (Hard Delete)
router.delete('/user/:id', verify, verifyAdmin, async (req, res) => {
    try {
        const userId = req.params.id;
        
        // 1. Delete User
        await User.findByIdAndDelete(userId);
        
        // 2. Delete Assets? (Optional: Keep them or burn them)
        await Asset.deleteMany({ owner_id: userId });
        
        // 3. Transactions are usually kept for ledger integrity, 
        // but if you want a clean wipe:
        // await Transaction.deleteMany({ user_id: userId });

        res.json({ success: true, message: "User Deleted" });
    } catch (err) {
        res.status(500).send("Delete Failed");
    }
});

module.exports = router;