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

interface AggregatedData {
    totalInvested: number;
    totalProfit: number;
    totalLoss: number;
    winTrades: number;
    lossTrades: number;
    totalTrades: number;
    portfolioEntries: any[];
}

interface OverallStats {
    totalInvested: number;
    totalProfit: number;
    totalLoss: number;
    totalWinTrades: number;
    totalLossTrades: number;
    maxDrawdown: number;
    peakBalance: number;
    currentBalance: number;
}

export const getVerifiedTrackRecord = async (req: Request, res: Response) => {
    try {
        const userPortfolios = await UserPortfolio.createQueryBuilder("userPortfolio")
            .orderBy("userPortfolio.created_at", "ASC")
            .getMany();

        const allTransactions = await Transaction.createQueryBuilder("transaction")
            .getMany();

        const monthlyData = new Map<string, AggregatedData>();
        const yearlyData = new Map<string, AggregatedData>();

        // Process portfolio data using helper functions
        processPortfolioData(userPortfolios, monthlyData, yearlyData);

        // Calculate overall statistics
        const overallStats = calculateOverallStats(allTransactions, userPortfolios);
        const { winRate, returnPercentage } = calculateRates(overallStats);

        // Format data for response
        const monthlyResults = formatPeriodData(monthlyData, 'monthly', true);
        const yearlyResults = formatPeriodData(yearlyData, 'yearly', false);
        const graphData = generateGraphData(monthlyData);
        
        const currentYearData = yearlyData.get(new Date().getFullYear().toString());
        const currentYearPerformance = formatCurrentYearPerformance(currentYearData);

        return sendSuccessResponse(res, 200, messages.viewData, {
            currentBalance: parseFloat(overallStats.currentBalance.toFixed(2)),
            totalInvested: parseFloat(overallStats.totalInvested.toFixed(2)),
            totalReturn: parseFloat((overallStats.totalProfit - overallStats.totalLoss).toFixed(2)),
            totalReturnPercentage: parseFloat(returnPercentage.toFixed(2)),

            winRate: parseFloat(winRate.toFixed(2)),
            maxDrawdown: parseFloat(overallStats.maxDrawdown.toFixed(2)),
            totalTrades: overallStats.totalWinTrades + overallStats.totalLossTrades,
            winTrades: overallStats.totalWinTrades,
            lossTrades: overallStats.totalLossTrades,
            profitFactor: calculateProfitFactor(overallStats.totalProfit, overallStats.totalLoss),

            currentYearPerformance,
            monthlyData: monthlyResults,
            yearlyData: yearlyResults,
            graphData
        });
    } catch (error) {
        console.error("Verified track record error:", error);
        return sendErrorResponse(res, 500, messages.errorMsg);
    }
};

// Helper function to process portfolio data
function processPortfolioData(
    userPortfolios: any[], 
    monthlyData: Map<string, AggregatedData>, 
    yearlyData: Map<string, AggregatedData>
) {
    userPortfolios.forEach(portfolio => {
        const date = new Date(portfolio.createdAt);
        const monthKey = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}`;
        const yearKey = date.getFullYear().toString();

        const monthData = getOrCreatePeriodData(monthlyData, monthKey);
        const yearData = getOrCreatePeriodData(yearlyData, yearKey);

        updatePeriodData(monthData, portfolio);
        updatePeriodData(yearData, portfolio);
    });
}

// Helper function to get or create period data
function getOrCreatePeriodData(dataMap: Map<string, AggregatedData>, key: string): AggregatedData {
    if (!dataMap.has(key)) {
        dataMap.set(key, {
            totalInvested: 0,
            totalProfit: 0,
            totalLoss: 0,
            winTrades: 0,
            lossTrades: 0,
            totalTrades: 0,
            portfolioEntries: []
        });
    }
    return dataMap.get(key)!;
}

// Helper function to update period data
function updatePeriodData(periodData: AggregatedData, portfolio: any) {
    periodData.totalInvested += portfolio.investedAmount;
    
    const profitLoss = portfolio.dailyProfitAmount;
    if (profitLoss > 0) {
        periodData.totalProfit += profitLoss;
        periodData.winTrades += 1;
    } else if (profitLoss < 0) {
        periodData.totalLoss += Math.abs(profitLoss);
        periodData.lossTrades += 1;
    }

    periodData.totalTrades += 1;
    periodData.portfolioEntries.push(portfolio);
}

// Helper function to calculate overall statistics
function calculateOverallStats(allTransactions: any[], userPortfolios: any[]): OverallStats {
    const stats: OverallStats = {
        totalInvested: 0,
        totalProfit: 0,
        totalLoss: 0,
        totalWinTrades: 0,
        totalLossTrades: 0,
        maxDrawdown: 0,
        peakBalance: 0,
        currentBalance: 0
    };

    // Calculate from transactions
    allTransactions.forEach(transaction => {
        if (transaction.isdepositAmount) {
            stats.totalInvested += transaction.depositAmount;
            stats.currentBalance += transaction.depositAmount;
        }
        if (transaction.iswithdrawAmount) {
            stats.currentBalance -= transaction.withdrawAmount;
        }
    });

    // Calculate from portfolios
    let runningBalance = stats.totalInvested;
    userPortfolios.forEach(portfolio => {
        const profitLoss = portfolio.dailyProfitAmount;
        runningBalance += profitLoss;

        if (profitLoss > 0) {
            stats.totalProfit += profitLoss;
            stats.totalWinTrades += 1;
        } else if (profitLoss < 0) {
            stats.totalLoss += Math.abs(profitLoss);
            stats.totalLossTrades += 1;
        }

        if (runningBalance > stats.peakBalance) {
            stats.peakBalance = runningBalance;
        }

        const drawdown = ((stats.peakBalance - runningBalance) / stats.peakBalance) * 100;
        if (drawdown > stats.maxDrawdown) {
            stats.maxDrawdown = drawdown;
        }
    });

    return stats;
}

// Helper function to calculate rates
function calculateRates(stats: OverallStats) {
    const totalTrades = stats.totalWinTrades + stats.totalLossTrades;
    const winRate = totalTrades > 0 ? (stats.totalWinTrades / totalTrades) * 100 : 0;
    
    const totalReturn = stats.totalProfit - stats.totalLoss;
    const returnPercentage = stats.totalInvested > 0 ? (totalReturn / stats.totalInvested) * 100 : 0;

    return { winRate, returnPercentage };
}

// Helper function to calculate profit factor (fixes nested ternary)
function calculateProfitFactor(totalProfit: number, totalLoss: number): number {
    if (totalLoss > 0) {
        return parseFloat((totalProfit / totalLoss).toFixed(2));
    }
    
    if (totalProfit > 0) {
        return totalProfit;
    }
    
    return 0;
}

// Helper function to format period data
function formatPeriodData(
    dataMap: Map<string, AggregatedData>, 
    type: string, 
    isMonthly: boolean
) {
    return Array.from(dataMap.entries()).map(([period, data]) => ({
        period,
        type,
        totalInvested: parseFloat(data.totalInvested.toFixed(2)),
        totalReturn: parseFloat((data.totalProfit - data.totalLoss).toFixed(2)),
        returnPercentage: calculateReturnPercentage(data.totalProfit, data.totalLoss, data.totalInvested),
        winRate: calculateWinRate(data.winTrades, data.totalTrades),
        totalTrades: data.totalTrades,
        winTrades: data.winTrades,
        lossTrades: data.lossTrades,
        profitFactor: calculateProfitFactor(data.totalProfit, data.totalLoss)
    })).sort((a, b) => isMonthly ? 
        b.period.localeCompare(a.period) : 
        parseInt(b.period) - parseInt(a.period)
    );
}

// Helper function to calculate return percentage (fixes nested ternary)
function calculateReturnPercentage(totalProfit: number, totalLoss: number, totalInvested: number): number {
    if (totalInvested <= 0) {
        return 0;
    }
    
    return parseFloat(((totalProfit - totalLoss) / totalInvested * 100).toFixed(2));
}

// Helper function to calculate win rate (fixes nested ternary)
function calculateWinRate(winTrades: number, totalTrades: number): number {
    if (totalTrades <= 0) {
        return 0;
    }
    
    return parseFloat((winTrades / totalTrades * 100).toFixed(2));
}

// Helper function to generate graph data
function generateGraphData(monthlyData: Map<string, AggregatedData>) {
    const graphData = [];
    const currentDate = new Date();
    
    for (let i = 11; i >= 0; i--) {
        const date = new Date(currentDate.getFullYear(), currentDate.getMonth() - i, 1);
        const monthKey = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}`;
        const monthData = monthlyData.get(monthKey);

        graphData.push({
            month: monthKey,
            monthName: date.toLocaleDateString('en-US', { month: 'short', year: 'numeric' }),
            balance: calculateMonthBalance(monthData),
            returnPercentage: calculateReturnPercentage(
                monthData?.totalProfit ?? 0, 
                monthData?.totalLoss ?? 0, 
                monthData?.totalInvested ?? 0
            ),
            totalTrades: monthData ? monthData.totalTrades : 0
        });
    }
    
    return graphData;
}

// Helper function to calculate month balance
function calculateMonthBalance(monthData: AggregatedData | undefined): number {
    if (!monthData) {
        return 0;
    }
    
    return parseFloat((monthData.totalInvested + monthData.totalProfit - monthData.totalLoss).toFixed(2));
}

// Helper function to format current year performance
function formatCurrentYearPerformance(currentYearData: AggregatedData | undefined) {
    if (!currentYearData) {
        return null;
    }

    return {
        invested: parseFloat(currentYearData.totalInvested.toFixed(2)),
        return: parseFloat((currentYearData.totalProfit - currentYearData.totalLoss).toFixed(2)),
        returnPercentage: calculateReturnPercentage(
            currentYearData.totalProfit, 
            currentYearData.totalLoss, 
            currentYearData.totalInvested
        ),
        winRate: calculateWinRate(currentYearData.winTrades, currentYearData.totalTrades),
        totalTrades: currentYearData.totalTrades
    };
}
