import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const isDev = process.env.NODE_ENV === "development";

function getR2Client() {
  return new S3Client({
    region: "auto",
    endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
    credentials: {
      accessKeyId: process.env.R2_ACCESS_KEY_ID!,
      secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
    },
  });
}

const DEV_BASE_URL = process.env.NEXTAUTH_URL ?? "http://localhost:3000";

export async function generateUploadUrl(
  key: string,
  contentType: string,
  expiresIn = 300
): Promise<string> {
  if (isDev) {
    return `${DEV_BASE_URL}/api/files/dev/${key}`;
  }
  const command = new PutObjectCommand({
    Bucket: process.env.R2_BUCKET_NAME!,
    Key: key,
    ContentType: contentType,
  });
  return getSignedUrl(getR2Client(), command, { expiresIn });
}

export async function generateDownloadUrl(
  key: string,
  expiresIn = 3600
): Promise<string> {
  if (isDev) {
    return `${DEV_BASE_URL}/api/files/dev/${key}`;
  }
  const command = new GetObjectCommand({ Bucket: process.env.R2_BUCKET_NAME!, Key: key });
  return getSignedUrl(getR2Client(), command, { expiresIn });
}

export function buildStorageKey(
  // Crewing adds "cv" (Phase 3a); "crew-document" / "contract" follow in later
  // phases — see Crewing-Implementation-Spec §4.5.
  type: "po-document" | "receipt" | "cv" | "crew-document" | "contract" | "po-pdf",
  ownerId: string,
  fileName: string
): string {
  const timestamp = Date.now();
  const safe = fileName.replace(/[^a-zA-Z0-9._-]/g, "_");
  return `${type}/${ownerId}/${timestamp}-${safe}`;
}

export function buildSignatureKey(userId: string, ext: string): string {
  return `signatures/${userId}.${ext}`;
}

/**
 * Storage key for a company branding asset (logo or stamp/seal).
 * Deterministic per company+type so a re-upload overwrites the previous file.
 */
export function buildCompanyAssetKey(
  companyId: string,
  type: "logo" | "stamp",
  ext: string
): string {
  return `company-assets/${companyId}/${type}.${ext}`;
}

/**
 * Upload a file buffer directly to storage (server-side).
 * In dev: writes to .dev-uploads/. In prod: PUTs to R2.
 */
export async function uploadBuffer(
  key: string,
  buffer: Buffer,
  contentType: string
): Promise<void> {
  if (isDev) {
    const fs = await import("fs/promises");
    const path = await import("path");
    const dir = path.join(process.cwd(), ".dev-uploads", ...key.split("/").slice(0, -1));
    const filePath = path.join(process.cwd(), ".dev-uploads", ...key.split("/"));
    await fs.mkdir(dir, { recursive: true });
    await fs.writeFile(filePath, buffer);
  } else {
    const { S3Client, PutObjectCommand } = await import("@aws-sdk/client-s3");
    const s3 = new S3Client({
      region: "auto",
      endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
      credentials: {
        accessKeyId: process.env.R2_ACCESS_KEY_ID!,
        secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
      },
    });
    await s3.send(new PutObjectCommand({
      Bucket: process.env.R2_BUCKET_NAME!,
      Key: key,
      Body: buffer,
      ContentType: contentType,
    }));
  }
}

/**
 * Fetch a stored file as a Buffer (server-side).
 */
export async function downloadBuffer(key: string): Promise<Buffer | null> {
  try {
    if (isDev) {
      const fs = await import("fs/promises");
      const path = await import("path");
      const filePath = path.join(process.cwd(), ".dev-uploads", ...key.split("/"));
      return await fs.readFile(filePath) as Buffer;
    } else {
      const url = await generateDownloadUrl(key, 60);
      const res = await fetch(url);
      if (!res.ok) return null;
      return Buffer.from(await res.arrayBuffer());
    }
  } catch {
    return null;
  }
}
