import type { Request, Response, NextFunction } from "express";
import { db } from "../db/db.js";
import { apiHits } from "../db/schema/apiHits.js";

type StripPasswords<T> = T extends Array<infer U>
    ? StripPasswords<U>[]
    : T extends object
    ? { [K in keyof T as Exclude<K, "password">]: StripPasswords<T[K]> }
    : T;

function stripPasswords<T>(input: T): StripPasswords<T> {
    if (Array.isArray(input)) {
        return input.map(stripPasswords) as StripPasswords<T>;
    } else if (input && typeof input === "object") {
        const entries = Object.entries(input as object)
            .filter(([key]) => key !== "password")
            .map(([key, value]) => [key, stripPasswords(value)]);
        return Object.fromEntries(entries) as StripPasswords<T>;
    }
    return input as StripPasswords<T>;
}

export function apiHitMiddleware(
    req: Request,
    res: Response,
    next: NextFunction
) {
    const start = Date.now();

    // When response is done sending, log the request + response info
    res.on("finish", async () => {
        try {
            await db.insert(apiHits).values({
                method: req.method,
                path: req.originalUrl,
                body: JSON.stringify(req.body ? stripPasswords(req.body) : {}),
                status: res.statusCode,
                ip: req.ip,
                duration: Date.now() - start,
                createdAt: new Date(),
            });
        } catch (err) {
            console.error("Failed to insert apiTracking log:", err);
        }
    });

    next();
}
