import { and, desc, eq, type SQL, sum } from "drizzle-orm";
import { cartoes, faturas, lancamentos } from "@/db/schema";
import { buildInvoicePaymentNote } from "@/lib/contas/constants";
import { db } from "@/lib/db";
import {
	INVOICE_PAYMENT_STATUS,
	type InvoicePaymentStatus,
} from "@/lib/faturas";

const toNumber = (value: string | number | null | undefined) => {
	if (typeof value === "number") {
		return value;
	}
	if (value === null || value === undefined) {
		return 0;
	}
	const parsed = Number(value);
	return Number.isNaN(parsed) ? 0 : parsed;
};

export async function fetchCardData(userId: string, cartaoId: string) {
	const card = await db.query.cartoes.findFirst({
		columns: {
			id: true,
			name: true,
			brand: true,
			closingDay: true,
			dueDay: true,
			logo: true,
			limit: true,
			status: true,
			note: true,
			contaId: true,
		},
		where: and(eq(cartoes.id, cartaoId), eq(cartoes.userId, userId)),
	});

	return card;
}

export async function fetchInvoiceData(
	userId: string,
	cartaoId: string,
	selectedPeriod: string,
): Promise<{
	totalAmount: number;
	invoiceStatus: InvoicePaymentStatus;
	paymentDate: Date | null;
}> {
	const [invoiceRow, totalRow] = await Promise.all([
		db.query.faturas.findFirst({
			columns: {
				id: true,
				period: true,
				paymentStatus: true,
			},
			where: and(
				eq(faturas.cartaoId, cartaoId),
				eq(faturas.userId, userId),
				eq(faturas.period, selectedPeriod),
			),
		}),
		db
			.select({ totalAmount: sum(lancamentos.amount) })
			.from(lancamentos)
			.where(
				and(
					eq(lancamentos.userId, userId),
					eq(lancamentos.cartaoId, cartaoId),
					eq(lancamentos.period, selectedPeriod),
				),
			),
	]);

	const totalAmount = toNumber(totalRow[0]?.totalAmount);
	const isInvoiceStatus = (
		value: string | null | undefined,
	): value is InvoicePaymentStatus =>
		!!value && ["pendente", "pago"].includes(value);

	const invoiceStatus = isInvoiceStatus(invoiceRow?.paymentStatus)
		? invoiceRow?.paymentStatus
		: INVOICE_PAYMENT_STATUS.PENDING;

	// Buscar data do pagamento se a fatura estiver paga
	let paymentDate: Date | null = null;
	if (invoiceStatus === INVOICE_PAYMENT_STATUS.PAID) {
		const invoiceNote = buildInvoicePaymentNote(cartaoId, selectedPeriod);
		const paymentLancamento = await db.query.lancamentos.findFirst({
			columns: {
				purchaseDate: true,
			},
			where: and(
				eq(lancamentos.userId, userId),
				eq(lancamentos.note, invoiceNote),
			),
		});
		paymentDate = paymentLancamento?.purchaseDate
			? new Date(paymentLancamento.purchaseDate)
			: null;
	}

	return { totalAmount, invoiceStatus, paymentDate };
}

export async function fetchCardLancamentos(filters: SQL[]) {
	return db.query.lancamentos.findMany({
		where: and(...filters),
		with: {
			pagador: true,
			conta: true,
			cartao: true,
			categoria: true,
		},
		orderBy: desc(lancamentos.purchaseDate),
	});
}
