import { and, eq, sql } from "drizzle-orm";
import { transactions } from "@/db/schema";
import {
	buildDashboardAdminPeriodFilters,
	excludeAutoGeneratedEntryNotes,
} from "@/features/dashboard/transaction-filters";
import { db } from "@/shared/lib/db";
import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id";
import { safeToNumber as toNumber } from "@/shared/utils/number";

export type PaymentMethodSummary = {
	paymentMethod: string;
	amount: number;
	percentage: number;
	transactions: number;
};

export type PaymentMethodsData = {
	methods: PaymentMethodSummary[];
};

export async function fetchPaymentMethods(
	userId: string,
	period: string,
): Promise<PaymentMethodsData> {
	const adminPayerId = await getAdminPayerId(userId);
	if (!adminPayerId) {
		return { methods: [] };
	}

	const rows = await db
		.select({
			paymentMethod: transactions.paymentMethod,
			totalAmount: sql<number>`coalesce(sum(${transactions.amount}), 0)`,
			transactions: sql<number>`count(${transactions.id})`,
		})
		.from(transactions)
		.where(
			and(
				...buildDashboardAdminPeriodFilters({
					userId,
					period,
					adminPayerId,
				}),
				eq(transactions.transactionType, "Despesa"),
				excludeAutoGeneratedEntryNotes(),
			),
		)
		.groupBy(transactions.paymentMethod);

	const summaries = rows.map((row: (typeof rows)[number]) => {
		const amount = Math.abs(toNumber(row.totalAmount));
		const transactions = Number(row.transactions ?? 0);

		return {
			paymentMethod: row.paymentMethod,
			amount,
			transactions,
		};
	});

	const overallTotal = summaries.reduce(
		(acc: number, item: (typeof summaries)[number]) => acc + item.amount,
		0,
	);

	const methods = summaries
		.map((item: (typeof summaries)[number]) => ({
			paymentMethod: item.paymentMethod,
			amount: item.amount,
			transactions: item.transactions,
			percentage:
				overallTotal > 0
					? Number(((item.amount / overallTotal) * 100).toFixed(2))
					: 0,
		}))
		.sort(
			(a: (typeof summaries)[number], b: (typeof summaries)[number]) =>
				b.amount - a.amount,
		);

	return {
		methods,
	};
}
