import { file } from "bun";
import { join } from "path";
import { config, MUSIC_DIR } from "../config";
import { state } from "../state";
import { getOrCreateUser } from "./helpers";

// GET /api/library - list all tracks
export function handleGetLibrary(req: Request, server: any): Response {
  const { user, headers } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Authentication required" }, { status: 401 });
  }
  const tracks = state.library.getAllTracks().map(t => ({
    id: t.id,
    filename: t.filename,
    title: t.title,
    artist: t.artist,
    album: t.album,
    duration: t.duration,
    replayGainDb: t.replayGainDb,
    replayPeak: t.replayPeak,
    available: t.available,
  }));
  return Response.json(tracks, { headers });
}

// POST /api/upload - upload audio file
export async function handleUpload(req: Request, server: any): Promise<Response> {
  const { user, headers } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Authentication required" }, { status: 401 });
  }

  try {
    const formData = await req.formData();
    const uploadedFile = formData.get("file");

    if (!uploadedFile || !(uploadedFile instanceof File)) {
      state.library.logActivity("upload_failed", { filename: "unknown" }, { id: user.id, username: user.username });
      return Response.json({ error: "No file provided" }, { status: 400 });
    }

    const validExts = [".mp3", ".ogg", ".flac", ".wav", ".m4a", ".aac", ".opus", ".wma", ".mp4"];
    const ext = uploadedFile.name.toLowerCase().match(/\.[^.]+$/)?.[0];
    if (!ext || !validExts.includes(ext)) {
      state.library.logActivity("upload_rejected", { filename: uploadedFile.name }, { id: user.id, username: user.username });
      return Response.json({ error: "Invalid audio format" }, { status: 400 });
    }

    const safeName = uploadedFile.name.replace(/[^a-zA-Z0-9._-]/g, "_");
    const destPath = join(config.musicDir, safeName);

    const existingFile = Bun.file(destPath);
    if (await existingFile.exists()) {
      state.library.logActivity("upload_duplicate", { filename: safeName }, { id: user.id, username: user.username });
      return Response.json({ error: "File already exists" }, { status: 409 });
    }

    const arrayBuffer = await uploadedFile.arrayBuffer();
    await Bun.write(destPath, arrayBuffer);

    console.log(`[Upload] ${user.username} uploaded: ${safeName}`);
    state.library.logActivity("upload", { filename: safeName }, { id: user.id, username: user.username });
    return Response.json({ success: true, filename: safeName }, { headers });
  } catch (e) {
    console.error("[Upload] Error:", e);
    state.library.logActivity("upload_error", { filename: "unknown" }, { id: user.id, username: user.username });
    return Response.json({ error: "Upload failed" }, { status: 500 });
  }
}

// GET /api/tracks/:id - serve audio file
export async function handleGetTrack(req: Request, server: any, identifier: string): Promise<Response> {
  const { user } = getOrCreateUser(req, server);
  if (!user) {
    return Response.json({ error: "Authentication required" }, { status: 401 });
  }
  
  if (identifier.includes("..")) return new Response("Forbidden", { status: 403 });

  let filepath: string;
  if (identifier.startsWith("sha256:")) {
    const trackPath = state.library.getFilePath(identifier);
    if (!trackPath) return new Response("Not found", { status: 404 });
    filepath = trackPath;
  } else {
    filepath = join(MUSIC_DIR, identifier);
  }

  const f = file(filepath);
  if (!(await f.exists())) return new Response("Not found", { status: 404 });

  const size = f.size;
  const range = req.headers.get("range");

  if (range) {
    const match = range.match(/bytes=(\d+)-(\d*)/);
    if (match) {
      const start = parseInt(match[1]);
      const end = match[2] ? parseInt(match[2]) : size - 1;
      const chunk = f.slice(start, end + 1);
      return new Response(chunk, {
        status: 206,
        headers: {
          "Content-Range": `bytes ${start}-${end}/${size}`,
          "Accept-Ranges": "bytes",
          "Content-Length": String(end - start + 1),
          "Content-Type": f.type || "audio/mpeg",
        },
      });
    }
  }

  return new Response(f, {
    headers: {
      "Accept-Ranges": "bytes",
      "Content-Length": String(size),
      "Content-Type": f.type || "audio/mpeg",
    },
  });
}
