"use server";

import { z } from "zod";
import { prisma } from "@/lib/prisma";
import { auth } from "@/auth";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { minioClient, bucketName } from "@/lib/minio"; // Import MinIO client
import { v4 as uuidv4 } from "uuid";

// Max file size (e.g., 5MB)
const MAX_FILE_SIZE = 5 * 1024 * 1024;
// Allowed image types
const ACCEPTED_IMAGE_TYPES = [
  "image/jpeg",
  "image/jpg",
  "image/png",
  "image/webp",
  "image/gif",
];

// Update schema: image is now optional File
const PostSchema = z.object({
  title: z.string().min(3, "Title must be at least 3 characters"),
  slug: z
    .string()
    .min(3, "Slug must be at least 3 characters")
    .regex(
      /^[a-z0-9]+(?:-[a-z0-9]+)*$/,
      "Slug must be lowercase alphanumeric with hyphens"
    ),
  content: z.string().min(10, "Content is too short"),
  excerpt: z.string().optional(),
  // Validate the image file
  image: z
    .instanceof(File)
    .optional()
    .refine(
      (file) => !file || file.size <= MAX_FILE_SIZE,
      `Max image size is 5MB.`
    )
    .refine(
      (file) => !file || ACCEPTED_IMAGE_TYPES.includes(file.type),
      "Only .jpg, .jpeg, .png, .webp and .gif formats are supported."
    ),
  published: z.boolean().optional(),
  tags: z.string().optional(), // Handle tags if needed
});

export type CreatePostState = {
  message: string | null;
  errors: {
    title?: string[];
    slug?: string[];
    content?: string[];
    image?: string[];
    tags?: string[];
    excerpt?: string[];
    _form?: string[];
  };
  previousInput?: {
    title?: string;
    slug?: string;
    content?: string;
    excerpt?: string;
    tags?: string;
    published?: boolean;
  };
};

// Helper function to upload to MinIO
async function uploadImageToMinio(file: File): Promise<string | null> {
  try {
    const fileExtension = file.name.split(".").pop();
    const fileName = `${uuidv4()}.${fileExtension}`;
    const buffer = Buffer.from(await file.arrayBuffer());
    await minioClient.putObject(bucketName, fileName, buffer, buffer.length, {
      "Content-Type": file.type,
    });
    const baseUrl = process.env.MINIO_BASE_URL?.replace(/\/+$/, "");
    const publicUrl = `${baseUrl}/${bucketName}/${fileName}`;
    return publicUrl;
  } catch (error) {
    console.error("MinIO Upload Error:", error);
    return null;
  }
}

export async function createPost(
  prevState: CreatePostState,
  formData: FormData
): Promise<CreatePostState> {
  const session = await auth();
  if (!session?.user?.id) {
    // Check for user ID specifically
    return { errors: { _form: ["Authentication required."] }, message: null };
  }

  // Store raw form data for potential error return
  const rawFormData = {
    title: formData.get("title")?.toString(),
    slug: formData.get("slug")?.toString(),
    content: formData.get("content")?.toString(),
    excerpt: formData.get("excerpt")?.toString(),
    tags: formData.get("tags")?.toString(),
    published: formData.get("published") === "on",
    image: formData.get("image"), // Keep image separate for validation
  };

  const imageFile = rawFormData.image;
  const validatedFields = PostSchema.safeParse({
    ...rawFormData, // Spread raw data (excluding image)
    // Pass the file object only if it's a File instance and has size > 0
    image:
      imageFile instanceof File && imageFile.size > 0 ? imageFile : undefined,
  });

  if (!validatedFields.success) {
    console.error(
      "Validation Errors:",
      validatedFields.error.flatten().fieldErrors
    );
    // Return previous input along with errors
    return {
      errors: validatedFields.error.flatten().fieldErrors,
      message: "Failed to create post due to validation errors.",
      previousInput: {
        // Exclude image file
        title: rawFormData.title,
        slug: rawFormData.slug,
        content: rawFormData.content,
        excerpt: rawFormData.excerpt,
        tags: rawFormData.tags,
        published: rawFormData.published,
      },
    };
  }

  const { title, slug, content, excerpt, image, published, tags } =
    validatedFields.data;

  // --- Handle Image Upload ---
  let uploadedImageUrl: string | null = null;
  if (image) {
    uploadedImageUrl = await uploadImageToMinio(image);
    if (!uploadedImageUrl) {
      // Return previous input on image upload failure
      return {
        errors: { image: ["Failed to upload image."] },
        message: null,
        previousInput: {
          title: rawFormData.title,
          slug: rawFormData.slug,
          content: rawFormData.content,
          excerpt: rawFormData.excerpt,
          tags: rawFormData.tags,
          published: rawFormData.published,
        },
      };
    }
  }
  // --- End Image Upload ---

  // Check if slug is unique
  const existingPost = await prisma.post.findUnique({ where: { slug } });
  if (existingPost) {
    // Return previous input on slug error
    return {
      errors: { slug: ["Slug already exists."] },
      message: null,
      previousInput: {
        title: rawFormData.title,
        slug: rawFormData.slug, // Keep the problematic slug to show the user
        content: rawFormData.content,
        excerpt: rawFormData.excerpt,
        tags: rawFormData.tags,
        published: rawFormData.published,
      },
    };
  }

  // --- Handle Tags ---
  // Example: Split comma-separated tags and connect/create them
  const tagConnections = tags
    ? await Promise.all(
        tags
          .split(",")
          .map((tag) => tag.trim())
          .filter(Boolean)
          .map((tagName) =>
            prisma.tag.upsert({
              where: { name: tagName },
              update: {},
              create: { name: tagName },
            })
          )
      )
    : [];
  // --- End Handle Tags ---

  try {
    await prisma.post.create({
      data: {
        title,
        slug,
        content,
        excerpt: excerpt || content.substring(0, 150) + "...",
        imageUrl: uploadedImageUrl, // Store the MinIO URL
        published: published ?? false,
        authorId: session.user.id,
        tags: {
          // Connect tags
          connect: tagConnections.map((tag) => ({ id: tag.id })),
        },
      },
    });
  } catch (error) {
    console.error("Database Error:", error);
    // Return previous input on database error
    return {
      errors: { _form: ["Database Error: Failed to create post."] },
      message: null,
      previousInput: {
        title: rawFormData.title,
        slug: rawFormData.slug,
        content: rawFormData.content,
        excerpt: rawFormData.excerpt,
        tags: rawFormData.tags,
        published: rawFormData.published,
      },
    };
  }

  revalidatePath("/tech-talk");
  redirect(`/tech-talk/${slug}`);
}
