"use server";

import { revalidatePath } from "next/cache";
import { normalizeMediaUrl } from "./media";
import { prisma } from "./prisma";
import { requireCurrentUser, userIsAdmin } from "./session";
import { getAppSettings } from "./settings";

export async function addMediaToRoom(formData: FormData) {
  const user = await requireCurrentUser();
  const roomId = String(formData.get("roomId") || "");
  const sourceUrl = String(formData.get("sourceUrl") || "").trim();

  if (!roomId || !sourceUrl) return;

  const room = await prisma.room.findFirst({
    where: {
      id: roomId,
      OR: [{ ownerId: user.id }, { members: { some: { userId: user.id } } }, { visibility: "PUBLIC" }]
    },
    select: { id: true, slug: true }
  });

  if (!room) return;

  const settings = await getAppSettings();
  const media = normalizeMediaUrl(sourceUrl);
  if (!settings.allowedProviders.includes(media.provider)) return;

  const nextPosition = await prisma.mediaSource.count({ where: { roomId: room.id } });

  const created = await prisma.mediaSource.create({
    data: {
      roomId: room.id,
      submitterId: user.id,
      provider: media.provider,
      originalUrl: media.originalUrl,
      playbackUrl: media.playbackUrl,
      thumbnailUrl: media.thumbnailUrl,
      queuePosition: nextPosition + 1,
      title: media.originalUrl
    }
  });

  await prisma.room.update({
    where: { id: room.id },
    data: {
      currentState: {
        provider: media.provider,
        originalUrl: media.originalUrl,
        playbackUrl: media.playbackUrl,
        mediaSourceId: created.id,
        status: "PAUSED",
        position: 0,
        rate: 1,
        updatedBy: user.username,
        updatedAt: Date.now()
      }
    }
  });

  revalidatePath(`/rooms/${encodeURIComponent(room.slug)}`);
  revalidatePath("/dashboard");
}

export async function removeMediaFromRoom(formData: FormData) {
  const { room, media } = await requireMediaManager(formData);
  if (!room || !media) return;

  await prisma.mediaSource.delete({ where: { id: media.id } });
  await normalizeQueue(room.id);
  revalidateRoom(room.slug);
}

export async function moveMediaUp(formData: FormData) {
  await moveMedia(formData, -1);
}

export async function moveMediaDown(formData: FormData) {
  await moveMedia(formData, 1);
}

export async function setCurrentMedia(formData: FormData) {
  const user = await requireCurrentUser();
  const mediaId = String(formData.get("mediaId") || "");
  if (!mediaId) return;

  const media = await prisma.mediaSource.findUnique({
    where: { id: mediaId },
    include: {
      room: {
        select: {
          id: true,
          slug: true,
          ownerId: true,
          visibility: true,
          members: { where: { userId: user.id }, select: { canManage: true } }
        }
      }
    }
  });

  if (!media || !canUseRoom(user.id, media.room, user)) return;

  await prisma.room.update({
    where: { id: media.roomId },
    data: {
      currentState: {
        provider: media.provider,
        originalUrl: media.originalUrl,
        playbackUrl: media.playbackUrl,
        mediaSourceId: media.id,
        status: "PLAYING",
        position: 0,
        rate: 1,
        updatedBy: user.username,
        updatedAt: Date.now()
      }
    }
  });

  revalidateRoom(media.room.slug);
}

async function moveMedia(formData: FormData, direction: -1 | 1) {
  const { room, media } = await requireMediaManager(formData);
  if (!room || !media) return;

  const queue = await prisma.mediaSource.findMany({
    where: { roomId: room.id },
    orderBy: [{ queuePosition: "asc" }, { createdAt: "asc" }, { id: "asc" }],
    select: { id: true }
  });
  const index = queue.findIndex((item) => item.id === media.id);
  const target = index + direction;
  if (index < 0 || target < 0 || target >= queue.length) return;

  const reordered = [...queue];
  [reordered[index], reordered[target]] = [reordered[target], reordered[index]];
  await prisma.$transaction(
    reordered.map((item, itemIndex) =>
      prisma.mediaSource.update({
        where: { id: item.id },
        data: { queuePosition: itemIndex + 1 }
      })
    )
  );

  revalidateRoom(room.slug);
}

async function requireMediaManager(formData: FormData) {
  const user = await requireCurrentUser();
  const mediaId = String(formData.get("mediaId") || "");
  if (!mediaId) return { room: null, media: null };

  const media = await prisma.mediaSource.findUnique({
    where: { id: mediaId },
    include: {
      room: {
        select: {
          id: true,
          slug: true,
          ownerId: true,
          visibility: true,
          members: { where: { userId: user.id }, select: { canManage: true } }
        }
      }
    }
  });

  if (!media || !canManageRoom(user.id, media.room, user)) return { room: null, media: null };
  return { room: media.room, media };
}

function canUseRoom(
  userId: string,
  room: { ownerId: string | null; visibility: string; members: Array<{ canManage: boolean }> },
  user?: Awaited<ReturnType<typeof requireCurrentUser>>
) {
  return room.ownerId === userId || Boolean(user && userIsAdmin(user)) || room.visibility === "PUBLIC" || room.members.length > 0;
}

function canManageRoom(
  userId: string,
  room: { ownerId: string | null; members: Array<{ canManage: boolean }> },
  user?: Awaited<ReturnType<typeof requireCurrentUser>>
) {
  return room.ownerId === userId || Boolean(user && userIsAdmin(user)) || room.members.some((member) => member.canManage);
}

async function normalizeQueue(roomId: string) {
  const queue = await prisma.mediaSource.findMany({
    where: { roomId },
    orderBy: [{ queuePosition: "asc" }, { createdAt: "asc" }, { id: "asc" }],
    select: { id: true }
  });
  if (queue.length === 0) return;
  await prisma.$transaction(
    queue.map((item, index) =>
      prisma.mediaSource.update({
        where: { id: item.id },
        data: { queuePosition: index + 1 }
      })
    )
  );
}

function revalidateRoom(slug: string) {
  revalidatePath(`/rooms/${encodeURIComponent(slug)}`);
  revalidatePath("/dashboard");
  revalidatePath("/rooms");
}
