import {
  createPlaylist,
  getPlaylist,
  getPlaylistsByUser,
  getPublicPlaylists,
  getPlaylistByShareToken,
  updatePlaylist,
  deletePlaylist,
  setPlaylistTracks,
  addTracksToPlaylist,
  removeTrackFromPlaylist,
  removeTracksFromPlaylist,
  movePlaylistTracks,
  insertTracksToPlaylistAt,
  generatePlaylistShareToken,
  removePlaylistShareToken,
  findUserById,
} from "../db";
import { getOrCreateUser, userHasPermission } from "./helpers";

// GET /api/playlists - List user's + shared playlists
export function handleListPlaylists(req: Request, server: any): Response {
  const { user } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  const myPlaylists = getPlaylistsByUser(user.id);
  const sharedPlaylists = getPublicPlaylists(user.id);

  return Response.json({
    mine: myPlaylists,
    shared: sharedPlaylists,
  });
}

// POST /api/playlists - Create new playlist
export async function handleCreatePlaylist(req: Request, server: any): Promise<Response> {
  const { user } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (user.is_guest) {
    return Response.json({ error: "Guests cannot create playlists" }, { status: 403 });
  }

  let body: { name: string; description?: string };
  try {
    body = await req.json();
  } catch {
    return Response.json({ error: "Invalid JSON" }, { status: 400 });
  }

  if (!body.name?.trim()) {
    return Response.json({ error: "Name required" }, { status: 400 });
  }

  const playlist = createPlaylist(body.name.trim(), user.id, body.description?.trim() || "");
  return Response.json(playlist, { status: 201 });
}

// GET /api/playlists/:id - Get playlist details
export function handleGetPlaylist(req: Request, server: any, playlistId: string): Response {
  const { user } = getOrCreateUser(req, server);
  const playlist = getPlaylist(playlistId);

  if (!playlist) {
    return Response.json({ error: "Playlist not found" }, { status: 404 });
  }

  // Check access: owner, public, or has share token
  const url = new URL(req.url);
  const shareToken = url.searchParams.get("token");

  if (
    playlist.ownerId !== user?.id &&
    !playlist.isPublic &&
    playlist.shareToken !== shareToken
  ) {
    return Response.json({ error: "Access denied" }, { status: 403 });
  }

  // Include owner username
  const owner = findUserById(playlist.ownerId);
  return Response.json({
    ...playlist,
    ownerName: owner?.username || "Unknown",
  });
}

// PATCH /api/playlists/:id - Update playlist
export async function handleUpdatePlaylist(req: Request, server: any, playlistId: string): Promise<Response> {
  const { user } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  const playlist = getPlaylist(playlistId);
  if (!playlist) {
    return Response.json({ error: "Playlist not found" }, { status: 404 });
  }

  if (playlist.ownerId !== user.id && !user.is_admin) {
    return Response.json({ error: "Not your playlist" }, { status: 403 });
  }

  let body: { name?: string; description?: string; isPublic?: boolean };
  try {
    body = await req.json();
  } catch {
    return Response.json({ error: "Invalid JSON" }, { status: 400 });
  }

  updatePlaylist(playlistId, {
    name: body.name?.trim(),
    description: body.description?.trim(),
    isPublic: body.isPublic,
  });

  return Response.json({ ok: true });
}

// DELETE /api/playlists/:id - Delete playlist
export function handleDeletePlaylist(req: Request, server: any, playlistId: string): Response {
  const { user } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  const playlist = getPlaylist(playlistId);
  if (!playlist) {
    return Response.json({ error: "Playlist not found" }, { status: 404 });
  }

  if (playlist.ownerId !== user.id && !user.is_admin) {
    return Response.json({ error: "Not your playlist" }, { status: 403 });
  }

  deletePlaylist(playlistId);
  return Response.json({ ok: true });
}

// PATCH /api/playlists/:id/tracks - Modify tracks
export async function handleModifyPlaylistTracks(req: Request, server: any, playlistId: string): Promise<Response> {
  const { user } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  const playlist = getPlaylist(playlistId);
  if (!playlist) {
    return Response.json({ error: "Playlist not found" }, { status: 404 });
  }

  if (playlist.ownerId !== user.id && !user.is_admin) {
    return Response.json({ error: "Not your playlist" }, { status: 403 });
  }

  let body: { add?: string[]; remove?: number[]; set?: string[]; move?: number[]; to?: number; insertAt?: number };
  try {
    body = await req.json();
  } catch {
    return Response.json({ error: "Invalid JSON" }, { status: 400 });
  }

  // If 'set' is provided, replace entire track list
  if (body.set !== undefined) {
    setPlaylistTracks(playlistId, body.set);
    return Response.json({ ok: true });
  }

  // Move/reorder tracks
  if (body.move?.length && typeof body.to === "number") {
    movePlaylistTracks(playlistId, body.move, body.to);
    return Response.json({ ok: true });
  }

  // Remove tracks by position (bulk operation)
  if (body.remove?.length) {
    removeTracksFromPlaylist(playlistId, body.remove);
  }

  // Add tracks (at specific position or at end)
  if (body.add?.length) {
    if (typeof body.insertAt === "number") {
      insertTracksToPlaylistAt(playlistId, body.add, body.insertAt);
    } else {
      addTracksToPlaylist(playlistId, body.add);
    }
  }

  return Response.json({ ok: true });
}

// POST /api/playlists/:id/share - Generate share token
export function handleSharePlaylist(req: Request, server: any, playlistId: string): Response {
  const { user } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  const playlist = getPlaylist(playlistId);
  if (!playlist) {
    return Response.json({ error: "Playlist not found" }, { status: 404 });
  }

  if (playlist.ownerId !== user.id && !user.is_admin) {
    return Response.json({ error: "Not your playlist" }, { status: 403 });
  }

  const token = generatePlaylistShareToken(playlistId);
  return Response.json({ shareToken: token });
}

// DELETE /api/playlists/:id/share - Remove sharing
export function handleUnsharePlaylist(req: Request, server: any, playlistId: string): Response {
  const { user } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  const playlist = getPlaylist(playlistId);
  if (!playlist) {
    return Response.json({ error: "Playlist not found" }, { status: 404 });
  }

  if (playlist.ownerId !== user.id && !user.is_admin) {
    return Response.json({ error: "Not your playlist" }, { status: 403 });
  }

  removePlaylistShareToken(playlistId);
  return Response.json({ ok: true });
}

// GET /api/playlists/shared/:token - Get shared playlist by token
export function handleGetSharedPlaylist(req: Request, server: any, token: string): Response {
  const playlist = getPlaylistByShareToken(token);
  if (!playlist) {
    return Response.json({ error: "Playlist not found" }, { status: 404 });
  }

  const owner = findUserById(playlist.ownerId);
  return Response.json({
    ...playlist,
    ownerName: owner?.username || "Unknown",
  });
}

// POST /api/playlists/shared/:token/copy - Copy shared playlist to own
export function handleCopySharedPlaylist(req: Request, server: any, token: string): Response {
  const { user } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (user.is_guest) {
    return Response.json({ error: "Guests cannot copy playlists" }, { status: 403 });
  }

  const original = getPlaylistByShareToken(token);
  if (!original) {
    return Response.json({ error: "Playlist not found" }, { status: 404 });
  }

  const copy = createPlaylist(`${original.name} (Copy)`, user.id, original.description);
  setPlaylistTracks(copy.id, original.trackIds);

  return Response.json(copy, { status: 201 });
}
