import type { RowDataPacket } from 'mysql2';
import type { FilterHutangPiutang } from '$lib/types/hutang-piutang';
import type {
	FilterJenisCatatan,
	LaporanCatatanData,
	LaporanHutangPiutangDetailData,
	LaporanPenjualanData
} from '$lib/types/laporan-detail';
import type { Catatan, Penjualan } from '$lib/types/transaksi';
import db from '$lib/server/db';

interface TransaksiRow extends RowDataPacket {
	id: number;
	jenis: 'pendapatan' | 'pengeluaran';
	kategori: string;
	deskripsi: string;
	jumlah: number;
	barang_id: number | null;
	barang_nama: string | null;
	qty: number | null;
	tanggal: Date;
	created_at: Date;
}

interface HutangPiutangRow extends RowDataPacket {
	id: number;
	jenis: 'hutang' | 'piutang';
	nama: string;
	deskripsi: string;
	jumlah: number;
	sisa: number;
	status: 'belum_lunas' | 'lunas';
	tanggal: Date;
	jatuh_tempo: Date | null;
	created_at: Date;
}

function toNumber(value: unknown): number {
	return Number(value ?? 0);
}

function formatDateLocal(date: Date): string {
	const year = date.getFullYear();
	const month = String(date.getMonth() + 1).padStart(2, '0');
	const day = String(date.getDate()).padStart(2, '0');
	return `${year}-${month}-${day}`;
}

function mapPenjualanRow(row: TransaksiRow): Penjualan {
	return {
		id: row.id,
		kategori: row.kategori,
		deskripsi: row.deskripsi,
		jumlah: toNumber(row.jumlah),
		barang_id: row.barang_id ?? null,
		barang_nama: row.barang_nama ?? null,
		qty: row.qty != null ? toNumber(row.qty) : null,
		tanggal: formatDateLocal(new Date(row.tanggal)),
		created_at: new Date(row.created_at).toISOString()
	};
}

function mapCatatanRow(row: TransaksiRow): Catatan {
	return {
		id: row.id,
		jenis: row.jenis,
		kategori: row.kategori,
		deskripsi: row.deskripsi,
		jumlah: toNumber(row.jumlah),
		tanggal: formatDateLocal(new Date(row.tanggal)),
		created_at: new Date(row.created_at).toISOString()
	};
}

function mapHutangPiutangRow(row: HutangPiutangRow) {
	return {
		id: row.id,
		jenis: row.jenis,
		nama: row.nama,
		deskripsi: row.deskripsi,
		jumlah: toNumber(row.jumlah),
		sisa: toNumber(row.sisa),
		status: row.status,
		tanggal: formatDateLocal(new Date(row.tanggal)),
		jatuh_tempo: row.jatuh_tempo ? formatDateLocal(new Date(row.jatuh_tempo)) : null,
		created_at: new Date(row.created_at).toISOString()
	};
}

function getJenisCatatanConfig(jenis: FilterJenisCatatan): { sql: string; label: string } {
	switch (jenis) {
		case 'pendapatan':
			return { sql: "AND jenis = 'pendapatan'", label: 'Pemasukan' };
		case 'pengeluaran':
			return { sql: "AND jenis = 'pengeluaran'", label: 'Pengeluaran' };
		default:
			return { sql: '', label: 'Semua Jenis' };
	}
}

function getHutangPiutangFilterConfig(filter: FilterHutangPiutang): { sql: string; label: string } {
	switch (filter) {
		case 'hutang':
			return { sql: "AND jenis = 'hutang'", label: 'Hutang' };
		case 'piutang':
			return { sql: "AND jenis = 'piutang'", label: 'Piutang' };
		case 'belum_lunas':
			return { sql: "AND status = 'belum_lunas'", label: 'Belum Lunas' };
		default:
			return { sql: '', label: 'Semua' };
	}
}

export async function getLaporanPenjualanByDate(
	memberId: number,
	tanggalAwal: string,
	tanggalAkhir: string,
	memberNama: string,
	warungNama: string
): Promise<LaporanPenjualanData> {
	const [rows] = await db.query<TransaksiRow[]>(
		`
		SELECT t.id, t.kategori, t.deskripsi, t.jumlah, t.barang_id, t.qty, t.tanggal, t.created_at,
			b.nama AS barang_nama
		FROM transaksi t
		LEFT JOIN barang b ON b.id = t.barang_id
		WHERE t.member_id = ?
			AND t.sumber = 'penjualan'
			AND t.tanggal >= ?
			AND t.tanggal <= ?
		ORDER BY t.tanggal DESC, t.created_at DESC
		`,
		[memberId, tanggalAwal, tanggalAkhir]
	);

	const items = rows.map(mapPenjualanRow);
	const total = items.reduce((sum, item) => sum + item.jumlah, 0);

	return {
		warungNama,
		memberNama,
		tanggalAwal,
		tanggalAkhir,
		items,
		total,
		jumlah: items.length
	};
}

export async function getLaporanCatatanByDate(
	memberId: number,
	tanggalAwal: string,
	tanggalAkhir: string,
	jenis: FilterJenisCatatan,
	memberNama: string,
	warungNama: string
): Promise<LaporanCatatanData> {
	const jenisConfig = getJenisCatatanConfig(jenis);

	const [rows] = await db.query<TransaksiRow[]>(
		`
		SELECT id, jenis, kategori, deskripsi, jumlah, tanggal, created_at
		FROM transaksi
		WHERE member_id = ?
			AND sumber = 'catatan'
			AND tanggal >= ?
			AND tanggal <= ?
			${jenisConfig.sql}
		ORDER BY tanggal DESC, created_at DESC
		`,
		[memberId, tanggalAwal, tanggalAkhir]
	);

	const items = rows.map(mapCatatanRow);
	const totalPendapatan = items
		.filter((item) => item.jenis === 'pendapatan')
		.reduce((sum, item) => sum + item.jumlah, 0);
	const totalPengeluaran = items
		.filter((item) => item.jenis === 'pengeluaran')
		.reduce((sum, item) => sum + item.jumlah, 0);

	return {
		warungNama,
		memberNama,
		tanggalAwal,
		tanggalAkhir,
		jenis,
		jenisLabel: jenisConfig.label,
		items,
		totalPendapatan,
		totalPengeluaran,
		saldo: totalPendapatan - totalPengeluaran,
		jumlah: items.length
	};
}

export async function getLaporanHutangPiutangByDate(
	memberId: number,
	tanggalAwal: string,
	tanggalAkhir: string,
	filter: FilterHutangPiutang,
	memberNama: string,
	warungNama: string
): Promise<LaporanHutangPiutangDetailData> {
	const filterConfig = getHutangPiutangFilterConfig(filter);

	const [rows] = await db.query<HutangPiutangRow[]>(
		`
		SELECT id, jenis, nama, deskripsi, jumlah, sisa, status, tanggal, jatuh_tempo, created_at
		FROM hutang_piutang
		WHERE member_id = ?
			AND tanggal >= ?
			AND tanggal <= ?
			${filterConfig.sql}
		ORDER BY tanggal DESC, created_at DESC
		`,
		[memberId, tanggalAwal, tanggalAkhir]
	);

	const items = rows.map(mapHutangPiutangRow);
	const totalHutang = items
		.filter((item) => item.jenis === 'hutang')
		.reduce((sum, item) => sum + item.sisa, 0);
	const totalPiutang = items
		.filter((item) => item.jenis === 'piutang')
		.reduce((sum, item) => sum + item.sisa, 0);

	return {
		warungNama,
		memberNama,
		tanggalAwal,
		tanggalAkhir,
		filter,
		filterLabel: filterConfig.label,
		items,
		totalHutang,
		totalPiutang,
		jumlah: items.length
	};
}
