import "server-only";

import { randomUUID } from "node:crypto";
import { mkdir, writeFile } from "node:fs/promises";
import path from "node:path";
import OpenAI from "openai";
import { z } from "zod";

export const imageGenerationRequestSchema = z.object({
  prompt: z.string().min(20).max(32000),
  count: z.number().int().min(1).max(4).default(1),
  size: z
    .enum(["1024x1024", "1536x1024", "1024x1536", "auto"])
    .default("1536x1024"),
  quality: z.enum(["low", "medium", "high", "auto"]).default("auto"),
  outputFormat: z.enum(["png", "jpeg", "webp"]).default("webp"),
});

export type ImageGenerationRequest = z.infer<
  typeof imageGenerationRequestSchema
>;

const disallowedFactualTerms = [
  "bedroom",
  "bathroom",
  "kitchen",
  "exterior",
  "balcony",
  "view",
  "beach",
  "pool",
  "room",
  "amenity",
  "facility",
];

function assertNonFactualPrompt(prompt: string) {
  const normalized = prompt.toLowerCase();
  const matchedTerm = disallowedFactualTerms.find((term) =>
    normalized.includes(term)
  );

  if (matchedTerm) {
    throw new Error(
      `Generated assets cannot depict factual property content: ${matchedTerm}`
    );
  }
}

export async function generateEditorialAsset(
  input: ImageGenerationRequest,
  actorUserId: string
) {
  const request = imageGenerationRequestSchema.parse(input);
  assertNonFactualPrompt(request.prompt);

  if (process.env.IMAGE_GENERATION_ENABLED !== "true") {
    throw new Error("Image generation is disabled");
  }

  if (!process.env.OPENAI_API_KEY) {
    throw new Error("OPENAI_API_KEY is required");
  }

  const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
  const response = await client.images.generate({
    model: "gpt-image-2",
    prompt: request.prompt,
    n: request.count,
    size: request.size,
    quality: request.quality,
    output_format: request.outputFormat,
  });

  const outputDirectory =
    process.env.LOCAL_GENERATED_ASSET_DIR ?? "./storage/generated-assets";

  await mkdir(outputDirectory, { recursive: true });

  const writtenFiles = [];

  for (const image of response.data ?? []) {
    if (!image.b64_json) {
      throw new Error("OpenAI image response did not include base64 output");
    }

    const fileName = `${randomUUID()}.${request.outputFormat}`;
    const filePath = path.join(outputDirectory, fileName);

    await writeFile(filePath, Buffer.from(image.b64_json, "base64"));

    writtenFiles.push({
      path: filePath,
      format: request.outputFormat,
      model: "gpt-image-2",
      prompt: request.prompt,
      actorUserId,
      aiGenerated: true,
      approved: false,
    });
  }

  return writtenFiles;
}
