// src/controllers/lib/populators.ts
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
// All Rights Reserved

import assert from "node:assert";

import { NextFunction, Request, RequestHandler, Response } from "express";
import { DtpController } from "../../lib/controller.ts";

import DroneService from "../../services/drone.ts";
import UserService from "../../services/user.ts";
import { ChatSessionService } from "../../services/index.js";

export interface PopulateOptions {
  requireObject?: boolean;
}

export function populateChatSessionById(
  controller: DtpController,
  options?: PopulateOptions,
): RequestHandler {
  options = Object.assign({ requireObject: true }, options);
  return async function (
    _req: Request,
    res: Response,
    next: NextFunction,
    sessionId?: string,
  ): Promise<void> {
    assert(sessionId, "ChatSession ID is required");
    try {
      res.locals.chatSession = await ChatSessionService.getById(sessionId);
      if (options.requireObject && !res.locals.chatSession) {
        const error = new Error("ChatSession not found");
        error.statusCode = 404;
        throw error;
      }
      return next();
    } catch (error) {
      controller.log.error("failed to populate ChatSession by ID", {
        sessionId,
        error,
      });
      return next(error);
    }
  };
}

export function populateUserById(
  controller: DtpController,
  options?: PopulateOptions,
): RequestHandler {
  options = Object.assign({ requireObject: true }, options);
  return async function (
    _req: Request,
    res: Response,
    next: NextFunction,
    userId?: string,
  ): Promise<void> {
    assert(userId, "User ID is required");
    try {
      res.locals.userAccount = await UserService.getById(userId);
      if (options.requireObject && !res.locals.user) {
        const error = new Error("User not found");
        error.statusCode = 404;
        throw error;
      }
      return next();
    } catch (error) {
      controller.log.error("failed to populate User by ID", {
        userId,
        error,
      });
      return next(error);
    }
  };
}

export function populateDroneRegistrationById(
  controller: DtpController,
  options?: PopulateOptions,
): RequestHandler {
  options = Object.assign({ requireObject: true }, options);
  return async function (
    _req: Request,
    res: Response,
    next: NextFunction,
    registrationId?: string,
  ): Promise<void> {
    assert(registrationId, "Drone registration ID is required");
    try {
      res.locals.registration = await DroneService.getById(registrationId);
      return next();
    } catch (error) {
      controller.log.error("failed to populate User by ID", {
        registrationId,
        error,
      });
      return next(error);
    }
  };
}
