import { BadRequestError, NotFoundError } from "../../common/errors/http-errors";
import { prisma } from "../../config/prisma";
import * as repo from "./task-document.repo";

async function getClientContext(userId: string) {
  const client = await prisma.client.findUnique({
    where: { userId },
    select: { id: true },
  });
  if (!client) throw new BadRequestError("Client profile not found");
  return client;
}

function getClientId(client: Awaited<ReturnType<typeof getClientContext>>) {
  if (!client) throw new BadRequestError("Client profile not found");
  return client.id;
}

export async function uploadDocuments(userId: string, taskId: string, files: Express.Multer.File[]) {
  if (!files?.length) throw new BadRequestError("No files uploaded");

  const client = await getClientContext(userId);
  const clientId = getClientId(client);
  const task = await repo.findTaskForClient(taskId, clientId);
  if (!task) throw new NotFoundError("Task not found");

  const year = new Date().getFullYear();
  const folder = await repo.getOrCreateYearFolder(clientId, year);

  const docs = files.map((file: any) => ({
    clientId,
    folderId: folder.id,
    taskId,
    fileName: file.originalname,
    fileUrl: file.path,
    fileType: file.mimetype,
    fileSizeKb: Math.round(file.size / 1024),
    uploadedByUserId: userId,
  }));

  await repo.createDocuments(docs);
  return repo.findDocumentsByTask(taskId, clientId);
}

export async function getDocuments(userId: string, taskId: string) {
  const client = await getClientContext(userId);
  const clientId = getClientId(client);
  const task = await repo.findTaskForClient(taskId, clientId);
  if (!task) throw new NotFoundError("Task not found");
  return repo.findDocumentsByTask(taskId, clientId);
}

export async function deleteDocument(userId: string, taskId: string, documentId: string) {
  const client = await getClientContext(userId);
  const clientId = getClientId(client);
  const task = await repo.findTaskForClient(taskId, clientId);
  if (!task) throw new NotFoundError("Task not found");
  const doc = await repo.findDocumentForClient(documentId, taskId, clientId);
  if (!doc) throw new NotFoundError("Document not found");
  await repo.deleteDocument(documentId);
  return repo.findDocumentsByTask(taskId, clientId);
}

// ── ADMIN ────────────────────────────────────────────────────

async function getAdminOrgContext(userId: string) {
  const user = await prisma.user.findUnique({
    where: { id: userId },
    select: { organizationId: true, role: true },
  });
  if (!user?.organizationId) throw new BadRequestError("Admin organization not found");
  if (!["ADMIN", "SUPER_ADMIN"].includes(user.role)) throw new BadRequestError("Access denied");
  return { organizationId: user.organizationId };
}

export async function adminUploadDocuments(userId: string, taskId: string, files: Express.Multer.File[]) {
  if (!files?.length) throw new BadRequestError("No files uploaded");
  const { organizationId } = await getAdminOrgContext(userId);
  const task = await prisma.task.findFirst({ where: { id: taskId, organizationId } });
  if (!task) throw new NotFoundError("Task not found");

  const year = new Date().getFullYear();
  const folder = await repo.getOrCreateYearFolder(task.clientId, year);

  const docs = files.map((file: any) => ({
    clientId: task.clientId,
    folderId: folder.id,
    taskId,
    fileName: file.originalname,
    fileUrl: file.path,
    fileType: file.mimetype,
    fileSizeKb: Math.round(file.size / 1024),
    uploadedByUserId: userId,
  }));

  await repo.createDocuments(docs);
  return repo.findDocumentsByTaskAdmin(taskId);
}

export async function adminDeleteDocument(userId: string, taskId: string, documentId: string) {
  const { organizationId } = await getAdminOrgContext(userId);
  const task = await prisma.task.findFirst({ where: { id: taskId, organizationId } });
  if (!task) throw new NotFoundError("Task not found");
  const doc = await prisma.document.findFirst({ where: { id: documentId, taskId } });
  if (!doc) throw new NotFoundError("Document not found");
  await repo.deleteDocument(documentId);
  return repo.findDocumentsByTaskAdmin(taskId);
}