import { ConsoleUserAccessListRepository } from "@/internal/console-user-access-list/console-user-access-list.repository";
import { ConsoleUserAccessListServices } from "@/internal/console-user-access-list/console-user-access-list.services";
import { ConsoleUserRepository } from "@/internal/console-users/console-users.repository";
import { logError } from "@/lib/logger";
import { error as errorResponse, success } from "@/lib/response";
import type {
  CreatePromoCodeRequest,
  ListPromoCodesQuery,
  UpdatePromoCodeRequest,
} from "@/v1/services/admin/promo-codes/promo-codes.schema";
import { PromoCodesService } from "@/v1/services/admin/promo-codes/promo-codes.service";
import type { Context } from "hono";

// Map upstream Updot status to a safe status we expose to the admin-console.
// CRITICAL: never expose 401 — the admin-console treats 401 as "our session
// expired" and force-logs the user out. Convert it to 502 (bad gateway) so
// the user stays logged in and just sees an error in the UI.
function safeStatus(err: any, fallback: number) {
  const status = typeof err?.status === "number" ? err.status : fallback;
  if (status === 401) return 502;
  return status;
}

export const createPromoCodeHandler = async (c: Context) => {
  try {
    const body = (await c.req.json()) as CreatePromoCodeRequest;

    const service = PromoCodesService.getInstance();
    const result = await service.createPromoCode(body);

    return success(c, result.data, result.message, 201);
  } catch (err: any) {
    const status = safeStatus(err, 400);
    return errorResponse(
      c,
      err?.message || "Failed to create promo code",
      status,
      err?.detail ?? err,
    );
  }
};

export const updatePromoCodeHandler = async (c: Context) => {
  try {
    const id = c.req.param("id");
    if (!id) {
      return errorResponse(c, "Promo code id is required", 400);
    }
    // logInfo(`updatePromoCodeHandler: id=${id}`);

    const body = (await c.req.json()) as UpdatePromoCodeRequest;
    const service = PromoCodesService.getInstance();
    const result = await service.updatePromoCode(id, body);

    return success(c, result.data, result.message, 200);
  } catch (err: any) {
    logError("Error in updatePromoCodeHandler:", err);
    const status = safeStatus(err, 400);
    return errorResponse(
      c,
      err?.message || "Failed to update promo code",
      status,
      err?.detail ?? err,
    );
  }
};

export const listPromoCodesHandler = async (c: Context) => {
  try {
    const query = c.req.query() as ListPromoCodesQuery;
    const service = PromoCodesService.getInstance();
    const result = await service.listPromoCodes(query);

    // Promocode Access List: scope the returned page to promo codes this user
    // is explicitly allowed to see (no rows for the user = unrestricted).
    // NOTE: Updot paginates upstream, so this only filters within the current
    // page — a restricted user's page may return fewer than `limit` items even
    // though later pages exist. Acceptable given the small (dozens) code counts.
    const consoleUserId = c.get("consoleUserId") as string | undefined;
    let data = result.data as { data?: any[]; pagination?: any } | undefined;
    if (consoleUserId && Array.isArray(data?.data)) {
      const accessListServices = ConsoleUserAccessListServices({
        ConsoleUserAccessListRepository: ConsoleUserAccessListRepository(
          c as any,
        ),
        ConsoleUserRepository: ConsoleUserRepository(c as any),
      });
      const allowedIds = await accessListServices.FilterAllowedPromoCodeIds(
        consoleUserId,
        data!.data!.map((pc: any) => pc.id),
      );
      if (allowedIds !== null) {
        const allowedSet = new Set(allowedIds);
        data = {
          ...data,
          data: data!.data!.filter((pc: any) => allowedSet.has(pc.id)),
        };
      }
    }

    return success(c, data, result.message, 200);
  } catch (err: any) {
    logError("Error in listPromoCodesHandler:", err);
    const status = safeStatus(err, 400);
    return errorResponse(
      c,
      err?.message || "Failed to list promo codes",
      status,
      err?.detail ?? err,
    );
  }
};

export const getPromoCodeByCodeHandler = async (c: Context) => {
  try {
    const code = c.req.param("code");
    if (!code) {
      return errorResponse(c, "Promo code code is required", 400);
    }
    const service = PromoCodesService.getInstance();
    const result = await service.getPromoCodeByCode(code);

    return success(c, result.data, result.message, 200);
  } catch (err: any) {
    logError("Error in getPromoCodeByCodeHandler:", err);
    const status = safeStatus(err, 400);
    return errorResponse(
      c,
      err?.message || "Failed to get promo code",
      status,
      err?.detail ?? err,
    );
  }
};

export const deletePromoCodeHandler = async (c: Context) => {
  try {
    const id = c.req.param("id");
    if (!id) {
      return errorResponse(c, "Promo code id is required", 400);
    }

    const service = PromoCodesService.getInstance();
    const result = await service.deletePromoCode(id);

    return success(c, result.data, result.message, 200);
  } catch (err: any) {
    logError("Error in deletePromoCodeHandler:", err);
    const status = safeStatus(err, 400);
    return errorResponse(
      c,
      err?.message || "Failed to delete promo code",
      status,
      err?.detail ?? err,
    );
  }
};
