import { NextResponse } from "next/server";
import { revalidatePath } from "next/cache";
import { AppwriteException, ID, Permission, Role } from "node-appwrite";
import { InputFile } from "node-appwrite/file";

import { logAudit } from "@/lib/appwrite/audit";
import {
  BUCKETS,
  DATABASE_ID,
  TABLES,
  type Job,
  type JobFileKind,
} from "@/lib/appwrite/schema";
import { createAdminClient } from "@/lib/appwrite/server";
import { requireRole, requireTenant } from "@/lib/appwrite/tenant-guard";

const MAX_FILE_BYTES = 200 * 1024 * 1024;

function classifyFile(mimeType: string | undefined, name: string): JobFileKind {
  const lower = (mimeType || name).toLowerCase();
  if (/\.(stl|obj|ply|3mf|dcm)$/i.test(name)) return "scan";
  if (lower.startsWith("image/") || /\.(png|jpe?g|webp|tiff?|heic|heif|bmp)$/i.test(name)) {
    return "image";
  }
  return "document";
}

function filePermissions(clinicTenantId: string, labTenantId: string): string[] {
  return [
    Permission.read(Role.team(clinicTenantId)),
    Permission.read(Role.team(labTenantId)),
    Permission.delete(Role.team(clinicTenantId, "owner")),
    Permission.delete(Role.team(clinicTenantId, "admin")),
    Permission.delete(Role.team(labTenantId, "owner")),
    Permission.delete(Role.team(labTenantId, "admin")),
  ];
}

async function loadJobForTenant(jobId: string, tenantId: string): Promise<Job | null> {
  try {
    const { tablesDB } = createAdminClient();
    const row = await tablesDB.getRow(DATABASE_ID, TABLES.jobs, jobId);
    const job = row as unknown as Job;
    if (job.clinicTenantId !== tenantId && job.labTenantId !== tenantId) return null;
    return job;
  } catch {
    return null;
  }
}

function errorMessage(e: unknown, fallback: string): string {
  if (e instanceof AppwriteException) return e.message || fallback;
  if (process.env.NODE_ENV !== "production" && e instanceof Error) {
    return `${fallback} (${e.message})`;
  }
  return fallback;
}

export async function POST(
  request: Request,
  ctx: { params: Promise<{ jobId: string }> },
) {
  const { jobId } = await ctx.params;
  if (!jobId) {
    return NextResponse.json({ ok: false, error: "İş bulunamadı." }, { status: 400 });
  }

  let tenantCtx;
  try {
    tenantCtx = await requireTenant();
    requireRole(tenantCtx, ["owner", "admin", "member"]);
  } catch {
    return NextResponse.json({ ok: false, error: "Yetkiniz yok." }, { status: 401 });
  }

  const job = await loadJobForTenant(jobId, tenantCtx.tenantId);
  if (!job) {
    return NextResponse.json({ ok: false, error: "İş bulunamadı." }, { status: 404 });
  }

  let formData: FormData;
  try {
    formData = await request.formData();
  } catch (e) {
    console.error("[POST /api/jobs/files] formData parse", e);
    return NextResponse.json(
      { ok: false, error: "İstek okunamadı." },
      { status: 400 },
    );
  }

  const files = formData
    .getAll("files")
    .filter((v): v is File => v instanceof File && v.size > 0);

  if (files.length === 0) {
    return NextResponse.json({ ok: false, error: "Dosya seçin." }, { status: 400 });
  }

  for (const f of files) {
    if (f.size > MAX_FILE_BYTES) {
      return NextResponse.json(
        { ok: false, error: `${f.name} 200MB sınırını aşıyor.` },
        { status: 400 },
      );
    }
  }

  const { storage, tablesDB } = createAdminClient();
  const uploadedFileIds: string[] = [];
  const createdRowIds: string[] = [];

  try {
    for (const f of files) {
      const fileId = ID.unique();
      const buffer = Buffer.from(await f.arrayBuffer());
      const inputFile = InputFile.fromBuffer(buffer, f.name);
      await storage.createFile({
        bucketId: BUCKETS.jobFiles,
        fileId,
        file: inputFile,
        permissions: filePermissions(job.clinicTenantId, job.labTenantId),
      });
      uploadedFileIds.push(fileId);

      const kind = classifyFile(f.type, f.name);
      const row = await tablesDB.createRow(
        DATABASE_ID,
        TABLES.jobFiles,
        ID.unique(),
        {
          jobId: job.$id,
          clinicTenantId: job.clinicTenantId,
          labTenantId: job.labTenantId,
          uploadedBy: tenantCtx.user.id,
          kind,
          fileId,
          name: f.name.slice(0, 255),
          size: f.size,
          mimeType: f.type ? f.type.slice(0, 100) : undefined,
        },
        filePermissions(job.clinicTenantId, job.labTenantId),
      );
      createdRowIds.push(row.$id);
    }

    await logAudit({
      tenantId: tenantCtx.tenantId,
      userId: tenantCtx.user.id,
      action: "create",
      entityType: "job_files",
      entityId: jobId,
      changes: { count: files.length },
    });

    revalidatePath(`/jobs/${jobId}`);
    return NextResponse.json({ ok: true, uploaded: files.length });
  } catch (e) {
    console.error("[POST /api/jobs/files]", e);
    for (const id of createdRowIds) {
      try {
        await tablesDB.deleteRow(DATABASE_ID, TABLES.jobFiles, id);
      } catch {
        /* ignore */
      }
    }
    for (const id of uploadedFileIds) {
      try {
        await storage.deleteFile({ bucketId: BUCKETS.jobFiles, fileId: id });
      } catch {
        /* ignore */
      }
    }
    return NextResponse.json(
      { ok: false, error: errorMessage(e, "Dosya yüklenemedi.") },
      { status: 500 },
    );
  }
}
