
"use client";

import React, { useState, useEffect } from 'react';
import { AdminLayout } from "@/components/layout/admin-layout";
import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/ui/card";
import { db } from '@/lib/firebase';
import { collection, query, where, getDocs, doc, updateDoc, getDoc, writeBatch, serverTimestamp, addDoc, runTransaction, deleteDoc, DocumentSnapshot } from 'firebase/firestore';
import { Loader2, Check, X, User, ArrowRight, Phone, FileImage, Trash2, Download } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useToast } from '@/hooks/use-toast';
import { format } from 'date-fns';
import Image from 'next/image';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import jsPDF from 'jspdf';
import autoTable from 'jspdf-autotable';
import Papa from 'papaparse';
import { addEarning } from '@/lib/earnings';


interface Deposit {
    id: string;
    userId: string;
    amount: number;
    method: string;
    network?: string;
    status: string;
    createdAt: any;
    user?: { email: string, uid: string, referredBy?: string };
    methodId?: string;
    details?: { [key: string]: string };
}

interface CommissionLevel {
  id: string;
  value: number;
  type: 'fixed' | 'percentage';
}

interface CurrencySettings {
  symbol: string;
  position: 'left' | 'right';
}

interface NotificationSettings {
    [key: string]: boolean;
}

export default function AdminPendingDepositsPage() {
    const [deposits, setDeposits] = useState<Deposit[]>([]);
    const [loading, setLoading] = useState(true);
    const [processingId, setProcessingId] = useState<string | null>(null);
    const [currency, setCurrency] = useState<CurrencySettings>({ symbol: '$', position: 'left' });
    const { toast } = useToast();
    const [notificationSettings, setNotificationSettings] = useState<NotificationSettings>({});
    const [logoUrl, setLogoUrl] = useState('');

    const fetchDeposits = async () => {
        if (!db) {
            setLoading(false);
            return;
        }
        setLoading(true);
        try {
            const generalSettingsDoc = await getDoc(doc(db, 'settings', 'general'));
            if (generalSettingsDoc.exists()) {
                setLogoUrl(generalSettingsDoc.data().logoUrl || '');
            }

            const currencyDoc = await getDoc(doc(db, "settings", "currency"));
            if (currencyDoc.exists()) {
              setCurrency(currencyDoc.data() as CurrencySettings);
            }
            
            const notificationSettingsDoc = await getDoc(doc(db, 'settings', 'notifications'));
            if (notificationSettingsDoc.exists()) {
                setNotificationSettings(notificationSettingsDoc.data());
            }

            const q = query(collection(db, "deposits"), where("status", "==", "pending"));
            const querySnapshot = await getDocs(q);
            const depositsData = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })) as Deposit[];

            // Fetch user data for each deposit
            const depositsWithUsers = await Promise.all(depositsData.map(async (deposit) => {
                const userDoc = await getDoc(doc(db, "users", deposit.userId));
                if (userDoc.exists()) {
                    return { ...deposit, user: userDoc.data() as { email: string, uid: string, referredBy?: string } };
                }
                return deposit;
            }));

            setDeposits(depositsWithUsers);
        } catch (error: any) {
            toast({ variant: 'destructive', title: 'Error fetching deposits', description: error.message });
        } finally {
            setLoading(false);
        }
    };

    useEffect(() => {
        fetchDeposits();
    }, []);

    const handleAction = async (deposit: Deposit, newStatus: 'completed' | 'rejected') => {
        if (!db || !deposit.user) return;
        setProcessingId(deposit.id);

        const depositRef = doc(db, "deposits", deposit.id);

        try {
            if (newStatus === 'completed') {
                // Fetch settings outside the transaction
                const referralSettingsDocRef = doc(db, 'settings', 'referral');
                const earningRulesDocRef = doc(db, 'settings', 'earningRules');
                
                const [referralSettingsDoc, earningRulesDoc] = await Promise.all([
                    getDoc(referralSettingsDocRef),
                    getDoc(earningRulesDocRef),
                ]);

                await runTransaction(db, async (transaction) => {
                    const depositDoc = await transaction.get(depositRef);
                    if (!depositDoc.exists() || depositDoc.data().status !== 'pending') {
                        throw new Error("This deposit has already been processed.");
                    }
                    
                    const userRef = doc(db, "users", deposit.userId);
                    const userDoc = await transaction.get(userRef);
                    if (!userDoc.exists()) throw new Error("User not found.");
                    
                    const refSettings = referralSettingsDoc.exists() ? referralSettingsDoc.data() : null;
                    const userData = userDoc.data();
                    const commissionLevels: CommissionLevel[] = refSettings?.depositLevels || [];
                    const referrerDocs: { id: string, doc: DocumentSnapshot }[] = [];

                    if (refSettings?.depositCommissionEnabled && userData.referredBy) {
                        let currentReferrerId: string | undefined = userData.referredBy;
                        for (let i = 0; i < commissionLevels.length; i++) {
                            if (!currentReferrerId) break;
                            const referrerSnap = await transaction.get(doc(db, "users", currentReferrerId));
                            if (referrerSnap.exists()) {
                                referrerDocs.push({ id: currentReferrerId, doc: referrerSnap });
                                currentReferrerId = referrerSnap.data()?.referredBy;
                            } else {
                                break;
                            }
                        }
                    }

                    const currentBalance = userData.balance || 0;
                    const finalAmount = deposit.amount;
                    transaction.update(userRef, { balance: currentBalance + finalAmount });
                    transaction.update(depositRef, { status: 'completed' });
                    
                    if (refSettings?.depositCommissionEnabled && referrerDocs.length > 0) {
                        for (let i = 0; i < referrerDocs.length; i++) {
                            const { id: referrerId, doc: referrerDoc } = referrerDocs[i];
                            const level = commissionLevels[i];
                            if (!level) continue;
                            const commissionAmount = level.type === 'fixed'
                                ? level.value
                                : (deposit.amount * level.value) / 100;
                            
                            if(commissionAmount > 0) {
                                await addEarning(transaction, referrerId, commissionAmount, referrerDoc, earningRulesDoc);
                                const commissionLogRef = doc(collection(db, 'referralCommissions'));
                                transaction.set(commissionLogRef, {
                                    referrerId: referrerId, referredUserId: deposit.userId,
                                    amount: commissionAmount, type: 'deposit', level: i + 1, date: serverTimestamp()
                                });
                            }
                        }
                    }
                });

                // Send notification AFTER the transaction is successful
                if (notificationSettings.depositApproved) {
                    await addDoc(collection(db, "notifications"), {
                        userId: deposit.userId,
                        title: "Deposit Approved",
                        description: `Your deposit of ${formatCurrency(deposit.amount)} has been approved and added to your wallet.`,
                        isRead: false,
                        createdAt: serverTimestamp(),
                        link: '/dashboard/finance/history',
                        type: 'depositApproved'
                    });
                }
            } else { // Rejected
                 const batch = writeBatch(db);
                 batch.update(depositRef, { status: 'rejected' });
                 if (notificationSettings.depositRejected) {
                    const notificationRef = doc(collection(db, "notifications"));
                    batch.set(notificationRef, {
                        userId: deposit.userId,
                        title: "Deposit Rejected",
                        description: `Your deposit of ${formatCurrency(deposit.amount)} has been rejected. Please contact support for more information.`,
                        isRead: false,
                        createdAt: serverTimestamp(),
                        link: '/dashboard/finance/history',
                        type: 'depositRejected'
                    });
                }
                await batch.commit();
            }
            
            toast({ title: 'Success', description: `Deposit has been ${newStatus}.` });
            fetchDeposits();
        } catch (error: any) {
             toast({ variant: 'destructive', title: 'Error', description: `Failed to update deposit: ${error.message || error}` });
        } finally {
            setProcessingId(null);
        }
    }
    
    const handleDelete = async (depositId: string) => {
        if (!db) return;
        setProcessingId(depositId);
        try {
            await deleteDoc(doc(db, "deposits", depositId));
            toast({ title: "Success", description: "Deposit record has been deleted." });
            fetchDeposits();
        } catch (error: any) {
            toast({ variant: "destructive", title: "Error", description: `Failed to delete record: ${error.message}` });
        } finally {
            setProcessingId(null);
        }
    }

    const formatCurrency = (amount: number) => {
        const value = (amount || 0).toFixed(2);
        return currency.position === 'left' ? `${currency.symbol}${value}` : `${value}${currency.symbol}`;
    }

    const downloadCSV = () => {
        const data = deposits.map(d => {
            const details = Object.entries(d.details || {}).reduce((acc, [key, val]) => {
                acc[key] = val;
                return acc;
            }, {} as {[key: string]: string});

            return {
                'User': d.user?.email || d.userId,
                'Amount': formatCurrency(d.amount),
                'Method': `${d.method} ${d.network ? `(${d.network})` : ''}`,
                'Date': d.createdAt?.seconds ? format(new Date(d.createdAt.seconds * 1000), "PPp") : 'N/A',
                ...details
            }
        });
        const csv = Papa.unparse(data);
        const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
        const link = document.createElement('a');
        link.href = URL.createObjectURL(blob);
        link.setAttribute('download', 'pending_deposits.csv');
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    };

    const getBase64FromUrl = (url: string): Promise<string> => {
        return new Promise((resolve, reject) => {
            const img = new Image();
            img.crossOrigin = 'Anonymous';
            img.onload = () => {
                const canvas = document.createElement('canvas');
                canvas.width = img.width;
                canvas.height = img.height;
                const ctx = canvas.getContext('2d');
                if (!ctx) {
                    return reject(new Error('Canvas context not available'));
                }
                ctx.drawImage(img, 0, 0);
                resolve(canvas.toDataURL('image/png'));
            };
            img.onerror = () => reject(new Error(`Failed to load image for PDF: ${url}`));
            img.src = url;
        });
    };

    const downloadPDF = async () => {
        const pdfDoc = new jsPDF();
        let startY = 15;

        const generalSettingsDoc = await getDoc(doc(db, 'settings', 'general'));
        const brandingData = generalSettingsDoc.exists() ? generalSettingsDoc.data() : {};
        const { 
            companyName = 'My App', 
            companySlogan = '', 
            logoUrl = '',
            pdfHeaderType = 'logo_and_text',
            pdfHeaderTextColor = '#000000',
            pdfSloganTextColor = '#555555'
        } = brandingData;

        if ((pdfHeaderType === 'logo_and_text' || pdfHeaderType === 'logo_only') && logoUrl) {
            try {
                const logoBase64 = await getBase64FromUrl(logoUrl);
                const imgProps = pdfDoc.getImageProperties(logoBase64);
                const imgWidth = 40;
                const imgHeight = (imgProps.height * imgWidth) / imgProps.width;
                pdfDoc.addImage(logoBase64, 'PNG', 14, startY, imgWidth, imgHeight);
                startY += imgHeight + 2;
            } catch (e) {
                console.error("Error adding logo to PDF", e);
            }
        }
        
        if (pdfHeaderType === 'logo_and_text' || pdfHeaderType === 'text_only') {
            if (pdfHeaderType === 'text_only' && !logoUrl) startY = 22;
             pdfDoc.setTextColor(pdfHeaderTextColor);
             pdfDoc.setFontSize(16).setFont('helvetica', 'bold').text(companyName, 14, startY);
             startY += 8;
             if (companySlogan) {
                 pdfDoc.setTextColor(pdfSloganTextColor);
                 pdfDoc.setFontSize(10).setFont('helvetica', 'normal').text(companySlogan, 14, startY);
                 startY += 6;
             }
        }
        
        startY += 5;
        pdfDoc.setTextColor(0,0,0);

        pdfDoc.setFontSize(12).setFont('helvetica', 'bold').text("Pending Deposits", 14, startY);
        autoTable(pdfDoc, {
            head: [['User', 'Amount', 'Method', 'Date', 'Details']],
            body: deposits.map(d => [
                d.user?.email || d.userId,
                formatCurrency(d.amount),
                `${d.method} ${d.network ? `(${d.network})` : ''}`,
                d.createdAt?.seconds ? format(new Date(d.createdAt.seconds * 1000), "PPp") : 'N/A',
                d.details ? Object.entries(d.details).map(([key, value]) => `${key.replace(/_/g, ' ')}: ${value}`).join('\n') : 'N/A'
            ]),
            startY: startY + 6,
        });
        pdfDoc.save('pending_deposits.pdf');
    };

  return (
    <AdminLayout>
      <div className="flex flex-col gap-8">
        <div className="flex justify-between items-center">
          <div>
            <h1 className="text-3xl font-bold font-headline tracking-tight">Pending Deposits</h1>
            <p className="text-muted-foreground">Review and process pending deposit requests.</p>
          </div>
           <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <Button><Download className="mr-2 h-4 w-4"/> Export</Button>
                </DropdownMenuTrigger>
                <DropdownMenuContent>
                    <DropdownMenuItem onSelect={downloadCSV}>Download CSV</DropdownMenuItem>
                    <DropdownMenuItem onSelect={() => downloadPDF()}>Download PDF</DropdownMenuItem>
                </DropdownMenuContent>
            </DropdownMenu>
        </div>
        <Card>
            <CardHeader>
                <CardTitle>Deposit Requests</CardTitle>
                <CardDescription>
                   Approve or reject deposit requests from users.
                </CardDescription>
            </CardHeader>
            <CardContent>
                 {loading ? (
                    <div className="flex justify-center items-center p-8">
                        <Loader2 className="h-8 w-8 animate-spin" />
                    </div>
                ) : deposits.length === 0 ? (
                    <p className="text-center text-muted-foreground p-8">No pending deposits.</p>
                ) : (
                    <div className="grid gap-6">
                        {deposits.map(deposit => (
                            <Card key={deposit.id} className="bg-muted/30">
                                <CardHeader>
                                    <div className="flex justify-between items-start">
                                        <div>
                                            <CardTitle className="text-2xl">{formatCurrency(deposit.amount)}</CardTitle>
                                            <CardDescription>via {deposit.method} {deposit.network ? `(${deposit.network})` : ''}</CardDescription>
                                        </div>
                                        <div className="text-right">
                                            <p className="text-sm font-semibold flex items-center gap-2"><User className="h-4 w-4" /> {deposit.user?.email || 'Unknown User'}</p>
                                            <p className="text-xs text-muted-foreground">UID: {deposit.userId}</p>
                                        </div>
                                    </div>
                                </CardHeader>
                                <CardContent>
                                    <h4 className="text-sm font-semibold mb-2">User Provided Details:</h4>
                                    <div className="text-sm bg-background p-3 rounded-md space-y-2">
                                       {deposit.details && Object.keys(deposit.details).length > 0 ? (
                                            Object.entries(deposit.details).map(([key, value]) => (
                                                <div key={key} className="grid grid-cols-3">
                                                    <span className="text-muted-foreground capitalize col-span-1">{key.replace(/_/g, ' ')}:</span>
                                                    {value.startsWith('data:image') ? (
                                                        <Dialog>
                                                            <DialogTrigger asChild>
                                                                <Button variant="outline" size="sm" className="w-fit"><FileImage className="mr-2 h-3 w-3"/> View Slip</Button>
                                                            </DialogTrigger>
                                                            <DialogContent className="max-w-2xl">
                                                                <DialogHeader>
                                                                    <DialogTitle>Deposit Slip</DialogTitle>
                                                                </DialogHeader>
                                                                <div className="my-4">
                                                                    <Image src={value} alt="Deposit slip" width={800} height={600} className="rounded-md object-contain" />
                                                                </div>
                                                            </DialogContent>
                                                        </Dialog>
                                                    ) : (
                                                        <span className="font-medium col-span-2 break-all">{value}</span>
                                                    )}
                                                </div>
                                            ))
                                       ) : (
                                           <p className="text-muted-foreground italic">No details provided by user.</p>
                                       )}
                                    </div>
                                </CardContent>
                                <CardFooter className="flex justify-between items-center bg-muted/50 p-4">
                                     <p className="text-xs text-muted-foreground">
                                        Requested on {format(new Date(deposit.createdAt.seconds * 1000), "PPpp")}
                                    </p>
                                    <div className="flex gap-2">
                                        <AlertDialog>
                                            <AlertDialogTrigger asChild>
                                                <Button size="sm" variant="destructive" disabled={processingId === deposit.id}>
                                                    <Trash2 className="mr-2 h-4 w-4" /> Delete
                                                </Button>
                                            </AlertDialogTrigger>
                                            <AlertDialogContent>
                                                <AlertDialogHeader>
                                                    <AlertDialogTitle>Are you sure?</AlertDialogTitle>
                                                    <AlertDialogDescription>This will permanently delete the deposit record. This action cannot be undone.</AlertDialogDescription>
                                                </AlertDialogHeader>
                                                <AlertDialogFooter>
                                                    <AlertDialogCancel>Cancel</AlertDialogCancel>
                                                    <AlertDialogAction onClick={() => handleDelete(deposit.id)}>Delete</AlertDialogAction>
                                                </AlertDialogFooter>
                                            </AlertDialogContent>
                                        </AlertDialog>
                                        <Button size="sm" variant="outline" className="bg-red-500/10 text-red-500 border-red-500/20 hover:bg-red-500/20 hover:text-red-500" onClick={() => handleAction(deposit, 'rejected')} disabled={processingId === deposit.id}>
                                            {processingId === deposit.id ? <Loader2 className="mr-2 h-4 w-4 animate-spin"/> : <X className="mr-2 h-4 w-4" />} Reject
                                        </Button>
                                        <Button size="sm" variant="outline" className="bg-green-500/10 text-green-500 border-green-500/20 hover:bg-green-500/20 hover:text-green-500" onClick={() => handleAction(deposit, 'completed')} disabled={processingId === deposit.id}>
                                            {processingId === deposit.id ? <Loader2 className="mr-2 h-4 w-4 animate-spin"/> : <Check className="mr-2 h-4 w-4" />} Approve
                                        </Button>
                                    </div>
                                </CardFooter>
                            </Card>
                        ))}
                    </div>
                )}
            </CardContent>
        </Card>
      </div>
    </AdminLayout>
  );
}
