import { Request, Response } from "express";
import { sendErrorResponse, sendSuccessResponse } from "../../utills/response";
import { messages } from "../../utills/common";
import { Transaction } from "../../database/transaction/transaction";
import { SelectQueryBuilder } from "typeorm";

// Helper function to apply tab and filter conditions
const applyTabFilters = (query: SelectQueryBuilder<Transaction>, tabValue: string, filterValue: string): SelectQueryBuilder<Transaction> => {
    if (tabValue === 'withdrawal requests') {
        query = query.andWhere("transaction.withdrawAmount > :zero", { zero: 0 });
        if (filterValue === 'approved') {
            query = query.andWhere("transaction.iswithdrawAmount = :isApproved", { isApproved: true });
        } else if (filterValue === 'pending') {
            query = query.andWhere("transaction.iswithdrawAmount = :isPending", { isPending: false });
        }
    } else if (tabValue === 'deposit') {
        query = query.andWhere("transaction.depositAmount > :zero", { zero: 0 });
        query = query.andWhere("transaction.isdepositAmount = :isDeposit", { isDeposit: true });
    } else if (tabValue === 'transactions') {
        query = applyTransactionFilters(query, filterValue);
    }
    return query;
};

// Helper function to apply transaction-specific filters
const applyTransactionFilters = (query: SelectQueryBuilder<Transaction>, filterValue: string): SelectQueryBuilder<Transaction> => {
    if (filterValue === 'deposit') {
        query = query.andWhere("transaction.depositAmount > :zero", { zero: 0 });
        query = query.andWhere("transaction.isdepositAmount = :isDeposit", { isDeposit: true });
    } else if (filterValue === 'withdraw' || filterValue === 'withdrawal') {
        query = query.andWhere("transaction.withdrawAmount > :zero", { zero: 0 });
        query = query.andWhere("transaction.iswithdrawAmount = :isWithdraw", { isWithdraw: true });
    } else if (filterValue === 'all' || !filterValue) {
        query = query.andWhere(
            "((transaction.depositAmount > :zero AND transaction.isdepositAmount = :isDeposit) OR (transaction.withdrawAmount > :zero AND transaction.iswithdrawAmount = :isWithdraw))",
            { zero: 0, isDeposit: true, isWithdraw: true }
        );
    }
    return query;
};

// Helper function to build search WHERE clause
const buildSearchClause = (): string => {
    return `(
        transaction.id LIKE :search OR
        CAST(transaction.totalInvestedAmount AS CHAR) LIKE :search OR
        CAST(transaction.withdrawAmount AS CHAR) LIKE :search OR
        CAST(transaction.depositAmount AS CHAR) LIKE :search OR
        transaction.created_at LIKE :search OR
        transaction.updated_at LIKE :search OR
        userId.name LIKE :search OR
        userId.referredBy LIKE :search OR
        userId.referredCode LIKE :search OR
        userId.accountName LIKE :search OR
        userId.accountNumber LIKE :search OR
        userId.bsbNumber LIKE :search OR
        userId.address LIKE :search OR
        userId.zipCode LIKE :search OR
        userId.country LIKE :search OR
        userId.state LIKE :search OR
        userId.city LIKE :search
    )`;
};

// Helper function to parse date from search term
const parseDateSearch = (searchStr: string): string => {
    const parsedDate = new Date(searchStr);
    if (!isNaN(parsedDate.getTime())) {
        const year = parsedDate.getFullYear();
        const month = String(parsedDate.getMonth() + 1).padStart(2, '0');
        const day = String(parsedDate.getDate()).padStart(2, '0');
        return `${year}-${month}-${day}`;
    }
    return '';
};

// Helper function to apply search filters
const applySearchFilter = (query: SelectQueryBuilder<Transaction>, search: string): SelectQueryBuilder<Transaction> => {
    const searchTerm = `%${search}%`;
    const dateSearchTerm = parseDateSearch(search);

    const searchClause = buildSearchClause();

    if (dateSearchTerm) {
        return query.andWhere(searchClause.replace('transaction.created_at LIKE :search', 'transaction.created_at LIKE :dateSearch')
            .replace('transaction.updated_at LIKE :search', 'transaction.updated_at LIKE :dateSearch'),
            { search: searchTerm, dateSearch: `%${dateSearchTerm}%` }
        );
    }

    return query.andWhere(searchClause, { search: searchTerm });
};

// get user transaction with pagination and search
export const getAllUserTransaction = async (req: Request, res: Response) => {
    try {
        // Extract and validate query parameters
        const { page = '1', limit = '10', search = '', tab = '', filter = '' } = req.query;
        const pageNum = Math.max(1, parseInt(page as string, 10));
        const limitNum = Math.max(1, Math.min(100, parseInt(limit as string, 10)));
        const skip = (pageNum - 1) * limitNum;

        // Build base query
        let transactionQuery = Transaction.createQueryBuilder("transaction")
            .leftJoinAndSelect("transaction.userId", "userId")
            .select([
                "transaction.id",
                "transaction.totalInvestedAmount",
                "transaction.iswithdrawAmount",
                "transaction.isdepositAmount",
                "transaction.created_at",
                "transaction.updated_at",
                "transaction.withdrawAmount",
                "transaction.depositAmount",
                // Only select safe user fields
                "userId.id",
                "userId.name",
                "userId.referredBy",
                "userId.referredCode",
                "userId.isAdmin",
                "userId.dob",
                "userId.accountName",
                "userId.accountNumber",
                "userId.bsbNumber",
                "userId.address",
                "userId.zipCode",
                "userId.profileImg",
                "userId.country",
                "userId.state",
                "userId.city",
                "userId.created_at",
                "userId.updated_at"
            ]);

        // Apply filters based on tab and dropdown selection
        const tabValue = (tab as string).toLowerCase();
        const filterValue = (filter as string).toLowerCase();
        transactionQuery = applyTabFilters(transactionQuery, tabValue, filterValue);

        // Apply search filter when search term is provided
        if (search && (search as string).length > 0) {
            transactionQuery = applySearchFilter(transactionQuery, search as string);
        }

        // Apply ordering and pagination
        const [transactions, totalCount] = await transactionQuery
            .orderBy("transaction.iswithdrawAmount", "ASC")
            .addOrderBy("transaction.created_at", "DESC")
            .skip(skip)
            .take(limitNum)
            .getManyAndCount();

        // Filter out zero amounts
        const filteredTransactions = transactions.map(transaction => {
            const { withdrawAmount, depositAmount, ...rest } = transaction;
            const result: any = { ...rest };

            if (withdrawAmount && withdrawAmount !== 0) {
                result.withdrawAmount = withdrawAmount;
            }
            if (depositAmount && depositAmount !== 0) {
                result.depositAmount = depositAmount;
            }

            return result;
        });

        // Calculate pagination metadata
        const totalPages = Math.ceil(totalCount / limitNum);

        return sendSuccessResponse(res, 200, messages.getUser, {
            transactions: filteredTransactions,
            pagination: {
                currentPage: pageNum,
                totalPages,
                totalCount,
                limit: limitNum
            }
        });

    } catch (error) {
        console.error("Error fetching transactions:", error);
        return sendErrorResponse(res, 500, messages.errorMsg);
    }
};

// get all user transactions for graph (no pagination, filter, search, or tab)
export const getAllUserTransactionGraph = async (req: Request, res: Response) => {
    try {
        const transactions = await Transaction.createQueryBuilder("transaction")
            .leftJoinAndSelect("transaction.userId", "userId")
            .select([
                "transaction.id",
                "transaction.totalInvestedAmount",
                "transaction.iswithdrawAmount",
                "transaction.isdepositAmount",
                "transaction.created_at",
                "transaction.updated_at",
                "transaction.withdrawAmount",
                "transaction.depositAmount",
                "userId.id",
                "userId.name",
                "userId.referredBy",
                "userId.referredCode",
                "userId.isAdmin",
                "userId.dob",
                "userId.accountName",
                "userId.accountNumber",
                "userId.bsbNumber",
                "userId.address",
                "userId.zipCode",
                "userId.profileImg",
                "userId.country",
                "userId.state",
                "userId.city",
                "userId.created_at",
                "userId.updated_at"
            ])
            .orderBy("transaction.created_at", "DESC")
            .getMany();

        // Filter out zero amounts
        const filteredTransactions = transactions.map(transaction => {
            const { withdrawAmount, depositAmount, ...rest } = transaction;
            const result: any = { ...rest };

            if (withdrawAmount && withdrawAmount !== 0) {
                result.withdrawAmount = withdrawAmount;
            }
            if (depositAmount && depositAmount !== 0) {
                result.depositAmount = depositAmount;
            }

            return result;
        });

        return sendSuccessResponse(res, 200, messages.getUser, {
            transactions: filteredTransactions,
            totalCount: filteredTransactions.length
        });

    } catch (error) {
        console.error("Error fetching transactions for graph:", error);
        return sendErrorResponse(res, 500, messages.errorMsg);
    }
};
