"use server";

import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { prisma } from "@/lib/prisma";
import { readSession } from "@/lib/session";
import { isAdmin, isWholesale } from "@/lib/roles";
import { toSessionUser } from "@/lib/users";
import { setSessionCookie } from "@/lib/session";

export async function followAction(userId: string) {
  const session = await readSession();
  if (!session) redirect("/login");
  if (session.id === userId) return;
  await prisma.follow.upsert({
    where: { followerId_followingId: { followerId: session.id, followingId: userId } },
    create: { followerId: session.id, followingId: userId },
    update: {},
  });
  revalidatePath(`/members/${userId}`);
  revalidatePath("/directory");
}

export async function unfollowAction(userId: string) {
  const session = await readSession();
  if (!session) redirect("/login");
  await prisma.follow.deleteMany({
    where: { followerId: session.id, followingId: userId },
  });
  revalidatePath(`/members/${userId}`);
}

export async function startThreadAction(userId: string, gemTitle?: string) {
  const session = await readSession();
  if (!session) redirect("/login");
  if (session.id === userId) redirect("/messages");

  const existing = await prisma.thread.findFirst({
    where: {
      AND: [
        { participants: { some: { userId: session.id } } },
        { participants: { some: { userId } } },
      ],
    },
  });
  if (existing) {
    if (gemTitle) {
      await prisma.thread.update({
        where: { id: existing.id },
        data: { gemTitle, updatedAt: new Date() },
      });
    }
    redirect(`/messages/${existing.id}`);
  }

  const thread = await prisma.thread.create({
    data: {
      gemTitle: gemTitle || null,
      participants: {
        create: [{ userId: session.id }, { userId }],
      },
    },
  });
  redirect(`/messages/${thread.id}`);
}

export async function startThreadForm(userId: string) {
  await startThreadAction(userId);
}

export async function requestListingAction(listingId: string) {
  const session = await readSession();
  if (!session) redirect(`/login?next=/search/${listingId}`);
  const listing = await prisma.listing.findUnique({ where: { id: listingId } });
  if (!listing) return;
  if (listing.wholesaleOnly && !isWholesale(session)) {
    redirect("/trade");
  }
  await startThreadAction(listing.sellerId, listing.title);
}

export async function sendMessageAction(threadId: string, formData: FormData) {
  const session = await readSession();
  if (!session) redirect("/login");
  const body = String(formData.get("body") || "").trim();
  const gemTitle = String(formData.get("gemTitle") || "").trim();
  if (!body) return;

  const part = await prisma.threadParticipant.findUnique({
    where: { threadId_userId: { threadId, userId: session.id } },
  });
  if (!part) return;

  await prisma.message.create({
    data: {
      threadId,
      senderId: session.id,
      body,
      gemTitle: gemTitle || null,
    },
  });
  await prisma.thread.update({
    where: { id: threadId },
    data: { updatedAt: new Date() },
  });
  revalidatePath(`/messages/${threadId}`);
}

export async function sendOfferAction(threadId: string, formData: FormData) {
  const session = await readSession();
  if (!session) redirect("/login");
  const amount = Number(formData.get("amount"));
  if (!Number.isFinite(amount) || amount <= 0) return;
  const part = await prisma.threadParticipant.findUnique({
    where: { threadId_userId: { threadId, userId: session.id } },
  });
  if (!part) return;
  await prisma.offer.create({
    data: { threadId, userId: session.id, amount },
  });
  await prisma.thread.update({
    where: { id: threadId },
    data: { dealStatus: "negotiating", updatedAt: new Date() },
  });
  revalidatePath(`/messages/${threadId}`);
}

export async function setDealStatusAction(threadId: string, status: string) {
  const session = await readSession();
  if (!session) redirect("/login");
  const allowed = ["open", "negotiating", "agreed", "ordered", "closed"];
  if (!allowed.includes(status)) return;
  const part = await prisma.threadParticipant.findUnique({
    where: { threadId_userId: { threadId, userId: session.id } },
  });
  if (!part && !isAdmin(session)) return;
  await prisma.thread.update({ where: { id: threadId }, data: { dealStatus: status } });
  revalidatePath(`/messages/${threadId}`);
}

export async function createPostAction(_prev: { error?: string } | null, formData: FormData) {
  const session = await readSession();
  if (!session) redirect("/login");
  const title = String(formData.get("title") || "").trim();
  const body = String(formData.get("body") || "").trim();
  const kind = String(formData.get("kind") || "update");
  if (!title || !body) return { error: "Add a title and a note." };
  const eventAtRaw = String(formData.get("eventAt") || "");
  const post = await prisma.post.create({
    data: {
      authorId: session.id,
      kind,
      title,
      body,
      location: String(formData.get("location") || "") || null,
      eventAt: eventAtRaw ? new Date(eventAtRaw) : null,
    },
  });
  revalidatePath("/feed");
  revalidatePath("/events");
  revalidatePath("/");
  redirect(`/feed/${post.id}`);
}

export async function replyToPostAction(postId: string, formData: FormData) {
  const session = await readSession();
  if (!session) redirect(`/login?next=/feed/${postId}`);
  const body = String(formData.get("body") || "").trim();
  if (!body) redirect(`/feed/${postId}?error=1`);
  const post = await prisma.post.findUnique({ where: { id: postId } });
  if (!post || post.hidden) redirect("/feed");
  await prisma.reply.create({
    data: { postId, authorId: session.id, body },
  });
  revalidatePath(`/feed/${postId}`);
  revalidatePath("/feed");
  revalidatePath("/");
  redirect(`/feed/${postId}`);
}

export async function placeBidAction(auctionId: string, formData: FormData): Promise<void> {
  const session = await readSession();
  if (!session) redirect("/login");
  const amount = Number(formData.get("amount"));
  const auction = await prisma.auction.findUnique({ where: { id: auctionId } });
  if (!auction) redirect("/auctions");
  if (auction.wholesaleOnly && session.role !== "wholesale" && session.role !== "admin") {
    redirect("/trade");
  }
  const now = new Date();
  if (now < auction.startsAt || now > auction.endsAt) {
    redirect(`/auctions/${auctionId}`);
  }
  const floor = Math.max(auction.currentBid + auction.minIncrement, auction.startingBid);
  if (!Number.isFinite(amount) || amount < floor) {
    redirect(`/auctions/${auctionId}`);
  }
  await prisma.$transaction([
    prisma.bid.create({ data: { auctionId, bidderId: session.id, amount } }),
    prisma.auction.update({
      where: { id: auctionId },
      data: { currentBid: amount, status: "live" },
    }),
  ]);
  revalidatePath(`/auctions/${auctionId}`);
  revalidatePath("/auctions");
}

export async function adminSetRoleAction(userId: string, formData: FormData) {
  const session = await readSession();
  if (!isAdmin(session)) return;
  const role = String(formData.get("role") || "member");
  const verificationStatus = String(formData.get("verificationStatus") || "pending");
  const wholesaleStatus = String(formData.get("wholesaleStatus") || "none");
  const featured = formData.get("featured") === "on";
  await prisma.user.update({
    where: { id: userId },
    data: { role, verificationStatus, wholesaleStatus, featured },
  });
  if (session && session.id === userId) {
    const user = await prisma.user.findUnique({ where: { id: userId } });
    if (user) await setSessionCookie(toSessionUser(user));
  }
  revalidatePath("/admin");
}

export async function adminCreateAuctionAction(formData: FormData) {
  const session = await readSession();
  if (!isAdmin(session)) return;
  const startingBid = Number(formData.get("startingBid") || 0);
  await prisma.auction.create({
    data: {
      title: String(formData.get("title") || "Untitled lot"),
      category: String(formData.get("category") || "medium"),
      description: String(formData.get("description") || ""),
      origin: String(formData.get("origin") || ""),
      certification: String(formData.get("certification") || ""),
      treatment: String(formData.get("treatment") || ""),
      startingBid,
      currentBid: startingBid,
      minIncrement: Number(formData.get("minIncrement") || 50),
      startsAt: new Date(String(formData.get("startsAt"))),
      endsAt: new Date(String(formData.get("endsAt"))),
      status: "scheduled",
      memberOnly: formData.get("memberOnly") === "on",
      wholesaleOnly: formData.get("wholesaleOnly") === "on",
    },
  });
  revalidatePath("/admin");
  revalidatePath("/auctions");
}

export async function adminAddWholesaleLotAction(formData: FormData) {
  const session = await readSession();
  if (!isAdmin(session)) return;
  await prisma.wholesaleLot.create({
    data: {
      title: String(formData.get("title") || "Lot"),
      origin: String(formData.get("origin") || ""),
      description: String(formData.get("description") || ""),
      wholesalePrice: Number(formData.get("wholesalePrice") || 0),
      quantity: Number(formData.get("quantity") || 1),
      certificate: String(formData.get("certificate") || ""),
      treatment: String(formData.get("treatment") || ""),
      privateOffer: formData.get("privateOffer") === "on",
    },
  });
  revalidatePath("/admin");
  revalidatePath("/trade");
}

export async function requestWholesaleLotAction(lotId: string) {
  const session = await readSession();
  if (!session || (session.role !== "wholesale" && session.role !== "admin")) {
    redirect("/trade");
  }
  const lot = await prisma.wholesaleLot.findUnique({ where: { id: lotId } });
  if (!lot) return;
  await prisma.wholesaleOrder.create({
    data: {
      userId: session.id,
      lotId: lot.id,
      title: lot.title,
      amount: lot.wholesalePrice,
      status: "inquiry",
    },
  });
  const steward = await prisma.user.findFirst({ where: { role: "admin" } });
  if (steward) {
    await startThreadAction(steward.id, lot.title);
  }
  revalidatePath("/trade");
}

export async function publishPost(formData: FormData): Promise<void> {
  const result = await createPostAction(null, formData);
  if (result?.error) {
    redirect("/feed?error=1");
  }
}

export async function hidePostAction(postId: string) {
  const session = await readSession();
  if (!isAdmin(session)) return;
  await prisma.post.update({ where: { id: postId }, data: { hidden: true } });
  revalidatePath("/feed");
  revalidatePath(`/feed/${postId}`);
  revalidatePath("/events");
  revalidatePath("/");
  revalidatePath("/admin");
  redirect("/feed");
}

