import type { Context } from "hono";
import { env } from "@/lib/env";
import * as crypto from "node:crypto";

const PY_BASE = env.GetString("CHATBOT_PYTHON_BASE_URL");
const SECRET = env.GetString("INTERNAL_SERVER_API_KEY");

/**
 * Creates an encrypted, timestamped payload for server-to-server authentication.
 * @returns The encrypted payload string or null if the secret key is not set.
 */
function createApiAuthPayload(): string | null {
  if (!SECRET) {
    // This will be logged once on server startup if the key is missing.
    return null;
  }

  const payload = JSON.stringify({
    key: SECRET,
    ts: Date.now(),
  });

  const iv = crypto.randomBytes(12); // Recommended IV size for AES-GCM
  const keyBuffer = Buffer.from(SECRET, "utf-8");

  const cipher = crypto.createCipheriv("aes-256-gcm", keyBuffer, iv);
  const encrypted = Buffer.concat([
    cipher.update(payload, "utf8"),
    cipher.final(),
  ]);
  const tag = cipher.getAuthTag();

  // Format: iv:encrypted_data:auth_tag
  return `${iv.toString("hex")}:${encrypted.toString("hex")}:${tag.toString("hex")}`;
}
/**
 * Fetches and parses JSON data from the Python API.
 * Used for getting the state of an entity for logging.
 * @param c - The Hono context.
 * @param path - The API path to fetch.
 * @returns The parsed JSON data.
 */
export const fetchFromPythonApi = async <T = any>(
  c: Context,
  path: string,
): Promise<{ success: boolean; data: T; error?: string }> => {
  const url = new URL(`${PY_BASE}${path}`);
  const cookie = c.req.header("Cookie") ?? "";
  const authPayload = createApiAuthPayload();

  const res = await fetch(url.toString(), {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      ...(cookie ? { Cookie: cookie } : {}),
      "x-admin-email": c.get("adminEmail") ?? "",
      // Add the security payload header
      ...(authPayload && { "x-api-payload": authPayload }),
    },
  });

  if (!res.ok) {
    const errorText = await res.text();
    console.error(
      `Failed to fetch from Python API (${path}): ${res.status} ${errorText}`,
    );
    return { success: false, data: null as T, error: errorText };
  }

  return res.json();
};

/**
 * A helper to proxy requests from a Hono controller to the Python Chatbot API.
 * It forwards relevant headers and handles response normalization.
 *
 * @param c - The Hono context.
 * @param path - The API path to call on the Python service (e.g., '/v1/admin-console/chatbot/prompts').
 * @param method - The HTTP method (e.g., 'GET', 'POST').
 * @param query - Optional URL query parameters.
 * @param body - Optional request body for POST/PUT requests.
 * @returns The Hono Response object.
 */
export const proxyToPythonApi = async (
  c: Context,
  path: string,
  method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH",
  query?: Record<string, string>,
  body?: any,
) => {
  const url = new URL(`${PY_BASE}${path}`);
  const authPayload = createApiAuthPayload();

  if (query) {
    for (const [k, v] of Object.entries(query)) url.searchParams.set(k, v);
  }

  const cookie = c.req.header("Cookie") ?? "";

  let res: Response;
  try {
    res = await fetch(url.toString(), {
      method,
      headers: {
        "Content-Type": "application/json",
        ...(cookie ? { Cookie: cookie } : {}),
        "x-admin-email": c.get("adminEmail") ?? "",
        ...(authPayload && { "x-api-payload": authPayload }),
      },
      body: body ? JSON.stringify(body) : undefined,
    });
  } catch (fetchErr) {
    const msg = fetchErr instanceof Error ? fetchErr.message : "Network error";
    const errBody = JSON.stringify({ success: false, message: `Python API unreachable: ${msg}`, data: null });
    return {
      response: new Response(errBody, { status: 502, headers: { "Content-Type": "application/json" } }),
      payload: { success: false, message: `Python API unreachable: ${msg}` },
      ok: false,
    };
  }

  const text = await res.text();

  let payload: any = null;
  try {
    payload = text ? JSON.parse(text) : null;
  } catch {
    payload = { success: false, message: "Non-JSON response", raw: text };
  }

  return {
    response: new Response(text, {
      status: res.status,
      headers: { "Content-Type": "application/json" },
    }),
    payload,
    ok: res.ok,
  };
};

/**
 * Proxies a multipart/form-data request to the Python API, preserving the
 * Content-Type header (including the multipart boundary).
 */
export const proxyMultipartToPythonApi = async (
  c: Context,
  path: string,
) => {
  const url = new URL(`${PY_BASE}${path}`);
  const authPayload = createApiAuthPayload();
  const contentType = c.req.header("Content-Type") ?? "";
  const cookie = c.req.header("Cookie") ?? "";

  let res: Response;
  try {
    res = await fetch(url.toString(), {
      method: "POST",
      headers: {
        "Content-Type": contentType,
        ...(cookie ? { Cookie: cookie } : {}),
        "x-admin-email": c.get("adminEmail") ?? "",
        ...(authPayload && { "x-api-payload": authPayload }),
      },
      body: c.req.raw.body,
      // @ts-ignore — duplex is required for streaming body in Node fetch
      duplex: "half",
    });
  } catch (fetchErr) {
    const msg = fetchErr instanceof Error ? fetchErr.message : "Network error";
    const errBody = JSON.stringify({ success: false, message: `Python API unreachable: ${msg}`, data: null });
    return {
      response: new Response(errBody, { status: 502, headers: { "Content-Type": "application/json" } }),
      payload: { success: false, message: `Python API unreachable: ${msg}` },
      ok: false,
    };
  }

  const text = await res.text();
  let payload: any = null;
  try {
    payload = text ? JSON.parse(text) : null;
  } catch {
    payload = { success: false, message: "Non-JSON response", raw: text };
  }

  return {
    response: new Response(text, {
      status: res.status,
      headers: { "Content-Type": "application/json" },
    }),
    payload,
    ok: res.ok,
  };
};