import { isAbsolute, join, relative, resolve, sep } from "node:path";
import {
  WorkspaceFileBoundaryError,
  readWorkspaceFileNoFollow,
} from "../security/workspaceFiles.js";

export interface DeliverableFile {
  readonly path: string;
  readonly name: string;
  readonly data: Buffer;
}

const DELIVERABLE_CPH_DIRECTORY = "inbox";

export async function resolveDeliverableFile(
  requestedPath: string,
  workspaceRoot: string,
  workspaceDir: string,
  maxBytes?: number,
): Promise<DeliverableFile | null> {
  const token = requestedPath.trim();
  if (token === "") return null;

  for (const candidate of candidatePaths(token)) {
    assertNotPlatformRuntimePath(candidate, workspaceDir);
    try {
      return await readWorkspaceFileNoFollow(workspaceRoot, workspaceDir, candidate, maxBytes);
    } catch (error) {
      if (!(error instanceof WorkspaceFileBoundaryError) || error.reason !== "not_found") {
        throw error;
      }
      // Try the explicit workspace/build fallback for a bare filename. No
      // candidate outside the project workspace is ever considered.
    }
  }
  return null;
}

function assertNotPlatformRuntimePath(candidate: string, workspaceDir: string): void {
  const workspace = resolve(workspaceDir);
  const target = isAbsolute(candidate) ? resolve(candidate) : resolve(workspace, candidate);
  const rel = relative(workspace, target);
  const components = rel.split(sep);
  if (components[0] === ".cph" && components[1] !== DELIVERABLE_CPH_DIRECTORY) {
    throw new WorkspaceFileBoundaryError(
      `platform runtime files cannot be delivered: ${candidate}`,
      candidate,
      "boundary",
    );
  }
}

function candidatePaths(token: string): string[] {
  if (isAbsolute(token)) return [token];
  const candidates = [token];
  if (!token.includes("/") && !token.includes("\\")) {
    candidates.push(join("build", token));
  }
  return [...new Set(candidates)];
}
