import {
	add,
	differenceInMonths,
	endOfMonth,
	format,
	fromUnixTime,
	getUnixTime,
	isBefore,
} from "date-fns";
import { it } from "date-fns/locale";
import { RefreshCcw } from "lucide-react";
import type { GetServerSideProps } from "next";
import Head from "next/head";
import toast from "react-hot-toast";
import { LoadingPage } from "~/components/loading";
import { Status500 } from "~/components/status-page";
import { Button } from "~/components/ui/button";
import {
	Table,
	TableBody,
	TableCell,
	TableHead,
	TableHeader,
	TableRow,
} from "~/components/ui/table";
import type { NextPageWithLayout } from "~/pages/_app";

import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper";
import { api } from "~/utils/api";

const reportTypeTitles: Record<string, string> = {
	"balance_change_from_activity.itemized": "Movimenti",
	"payouts.itemized": "Pagamenti",
	"balance.summary": "Riepilogo Saldo",
};

const reportStatusTitles: Record<string, string> = {
	succeeded: "Completato",
	pending: "In lavorazione",
	failed: "Fallito",
};

const START_DATE = new Date("2026-01-01");

/**
 * Pagina di gestione reports stripe per admin: /area-riservata/admin/stripe-reports
 */
const StripeReports: NextPageWithLayout = () => {
	const { data, isLoading, refetch } =
		api.stripe_reports.listReports.useQuery();
	const utils = api.useUtils();
	const { mutate: setupEstrattoConto } =
		api.stripe_reports.setupEstrattoConto.useMutation({
			onSuccess: async () => {
				toast.success("Report richiesto con successo");
				await utils.stripe_reports.listReports.invalidate();
			},
			onError: (error) => {
				toast.error(`Errore nella richiesta del report: ${error.message}`);
			},
		});
	const { mutate: generateEstrattoConto } =
		api.stripe_reports.generateEstrattoConto.useMutation({
			onMutate: () => {
				toast.loading("Generazione estratto conto in corso...", {
					id: "generate-pdf",
				});
			},
			onSuccess: async (res) => {
				if (!res.data) {
					toast.error("PDF non disponibile al momento. Riprova più tardi.", {
						id: "generate-pdf",
					});
					return;
				}
				toast.success("PDF generato con successo!", {
					id: "generate-pdf",
				});

				const binaryString = atob(res.data.pdf);
				const bytes = Uint8Array.from(binaryString, (c) => c.charCodeAt(0));
				const blob = new Blob([bytes], {
					type: "application/pdf",
				});
				const url = window.URL.createObjectURL(blob);
				const link = document.createElement("a");
				link.href = url;
				link.download = res.data.title;
				document.body.appendChild(link);
				link.click();
				link.remove();
				window.URL.revokeObjectURL(url);
				toast.dismiss("generate-pdf");
			},
			onError: (error) => {
				toast.error(`Errore nella generazione del report: ${error.message}`, {
					id: "generate-pdf",
				});
			},
		});
	const now = new Date();
	const monthsToShow = differenceInMonths(now, START_DATE) + 1;

	if (isLoading) return <LoadingPage />;
	if (!data) return <Status500 />;
	return (
		<>
			<Head>
				<title>Stripe Reports</title>
			</Head>

			<div className="mx-1 flex-1 overflow-auto">
				<div className="mx-auto space-y-8 pt-4">
					<div className="mx-3 flex-wrap items-center justify-between sm:flex">
						<div className="flex max-w-lg items-center gap-3">
							<h3 className="font-bold text-accent-foreground text-xl sm:text-2xl">
								Estratti Conto Stripe
							</h3>

							<button
								className="cursor-pointer"
								onClick={async () => await refetch()}
								type="button"
							>
								<RefreshCcw className="size-6" />
							</button>
						</div>
					</div>
					<div className="mx-4 flex flex-col">
						<h3 className="font-semibold text-lg">Estratti Conto</h3>
						<Table>
							<TableHeader>
								<TableRow className="grid grid-cols-2">
									<TableHead>Intervallo</TableHead>
									<TableHead>Stato</TableHead>
								</TableRow>
							</TableHeader>
							<TableBody>
								{Array.from({ length: monthsToShow }, (_, i) => {
									const m = add(START_DATE, { months: i });
									const em = endOfMonth(m);
									const hasReports = data.filter((report) => {
										if (
											!report.parameters?.interval_start ||
											!report.parameters?.interval_end
										) {
											return false;
										}
										const um = getUnixTime(m);
										const uem = getUnixTime(em);
										// controlla se il report è allineato al mese in esame
										return (
											um >= report.parameters.interval_start &&
											um <= report.parameters.interval_end &&
											uem >= report.parameters.interval_start &&
											uem <= report.parameters.interval_end
										);
									});

									const hasBudgetReport = hasReports
										.sort((a, b) => b.created - a.created)
										.filter((report) =>
											report.report_type.startsWith(
												"balance_change_from_activity.itemized",
											),
										);

									const hasValidBudgetReport = hasBudgetReport.find(
										(report) =>
											report.status === "succeeded" &&
											isBefore(
												now,
												fromUnixTime(report.result?.expires_at ?? 0),
											),
									);
									const hasSummaryReport = hasReports
										.sort((a, b) => b.created - a.created)
										.filter((report) =>
											report.report_type.startsWith("balance.summary"),
										);
									const hasValidSummaryReport = hasSummaryReport.find(
										(report) =>
											report.status === "succeeded" &&
											isBefore(
												now,
												fromUnixTime(report.result?.expires_at ?? 0),
											),
									);

									const hasReport =
										hasBudgetReport.length > 0 && hasSummaryReport.length > 0;

									const hasReportValid =
										hasValidBudgetReport && hasValidSummaryReport;

									return (
										<TableRow className="grid grid-cols-2" key={m.getTime()}>
											<TableCell>
												{format(m, "MMMM yyyy", { locale: it })}
											</TableCell>
											<TableCell>
												{!hasReportValid ? (
													<Button
														onClick={() => setupEstrattoConto({ start: m })}
														size="sm"
														variant={hasReport ? "destructive" : "default"}
													>
														{hasReport ? "Scaduto - Rigenera" : "Genera Report"}
													</Button>
												) : (
													<div className="flex items-center gap-2">
														<Button
															onClick={() => {
																if (
																	hasValidBudgetReport.result?.url &&
																	hasValidSummaryReport.result?.url
																) {
																	generateEstrattoConto({
																		movimentiUrl:
																			hasValidBudgetReport.result.url,
																		saldoUrl: hasValidSummaryReport.result.url,
																	});
																}
															}}
															size="sm"
															variant="success"
														>
															Disponibile - Apri Estratto Conto
														</Button>
														<Button
															onClick={() => setupEstrattoConto({ start: m })}
															size="sm"
															variant="outline"
														>
															Rigenera Stripe Report
														</Button>
													</div>
												)}
											</TableCell>
										</TableRow>
									);
								})}
							</TableBody>
						</Table>
					</div>
					<hr />
					<div className="mx-4 flex flex-col">
						<h3 className="font-semibold text-lg">Report Generati da Stripe</h3>
						<Table>
							<TableHeader>
								<TableRow>
									<TableHead>Creato il</TableHead>
									<TableHead>Tipo</TableHead>
									<TableHead>Intervallo</TableHead>
									<TableHead>Stato</TableHead>
									<TableHead>Scadenza</TableHead>
								</TableRow>
							</TableHeader>
							<TableBody>
								{data.map((report) => {
									const createdAt = fromUnixTime(report.created);
									const expiresAt = report.result?.expires_at
										? fromUnixTime(report.result.expires_at)
										: null;
									const intervalStart = report.parameters.interval_start
										? fromUnixTime(report.parameters.interval_start)
										: null;
									const intervalEnd = report.parameters.interval_end
										? fromUnixTime(report.parameters.interval_end)
										: null;

									const reportType = report.report_type.replace(/\.\d/gm, "");

									return (
										<TableRow key={report.id}>
											<TableCell>{format(createdAt, "dd/MM/yyyy")}</TableCell>
											<TableCell>
												{reportTypeTitles[reportType] || "Report Sconosciuto"}
											</TableCell>
											<TableCell>
												{intervalStart && intervalEnd
													? `${format(intervalStart, "dd/MM/yyyy")} - ${format(intervalEnd, "dd/MM/yyyy")}`
													: "N/A"}
											</TableCell>
											<TableCell>
												{reportStatusTitles[report.status] ||
													"Stato Sconosciuto"}
											</TableCell>
											<TableCell>
												{expiresAt ? format(expiresAt, "dd/MM/yyyy") : "N/A"}
											</TableCell>
										</TableRow>
									);
								})}
							</TableBody>
						</Table>
					</div>
				</div>
			</div>
		</>
	);
};

export const getServerSideProps = (async (context) => {
	const access_token = context.req.cookies.access_token;

	const helpers = await TrpcAuthedFetchingIstance({ access_token });
	if (helpers) {
		await helpers.trpc.stripe_reports.listReports.prefetch();
		return {
			props: {
				trpcState: helpers.trpc.dehydrate(),
			},
		};
	}
	return {
		props: {},
	};
}) satisfies GetServerSideProps;
export default StripeReports;
