/**
 * Mentor Workspace Service
 *
 * Manages mentor-applicant workspace: activation, messaging, file management,
 * and file promotion to official submissions. Operates on MentorAssignment,
 * MentorMessage, MentorFile, MentorFileComment, SubmissionPromotionEvent.
 */

import type { PrismaClient, Prisma } from '@prisma/client'
import { logAudit } from '@/server/utils/audit'

// ─── Types ──────────────────────────────────────────────────────────────────

type WorkspaceResult = { success: boolean; errors?: string[] }

// ─── Workspace Activation ───────────────────────────────────────────────────

/**
 * Activate a mentor workspace for a given assignment.
 */
export async function activateWorkspace(
  workspaceId: string,
  actorId: string,
  prisma: PrismaClient,
): Promise<WorkspaceResult> {
  try {
    const assignment = await prisma.mentorAssignment.findUnique({
      where: { id: workspaceId },
    })

    if (!assignment) {
      return { success: false, errors: ['Mentor assignment not found'] }
    }

    if (assignment.workspaceEnabled) {
      return { success: false, errors: ['Workspace is already enabled'] }
    }

    await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
      await tx.mentorAssignment.update({
        where: { id: workspaceId },
        data: {
          workspaceEnabled: true,
          workspaceOpenAt: new Date(),
        },
      })

      await tx.decisionAuditLog.create({
        data: {
          eventType: 'mentor_workspace.activated',
          entityType: 'MentorAssignment',
          entityId: workspaceId,
          actorId,
          detailsJson: {
            projectId: assignment.projectId,
            mentorId: assignment.mentorId,
          },
          snapshotJson: { timestamp: new Date().toISOString(), emittedBy: 'mentor-workspace' },
        },
      })

      await logAudit({
        prisma: tx,
        userId: actorId,
        action: 'WORKSPACE_ACTIVATE',
        entityType: 'MentorAssignment',
        entityId: workspaceId,
        detailsJson: { projectId: assignment.projectId },
      })
    })

    return { success: true }
  } catch (error) {
    console.error('[MentorWorkspace] activateWorkspace failed:', error)
    return {
      success: false,
      errors: [error instanceof Error ? error.message : 'Unknown error'],
    }
  }
}

// ─── Messaging ──────────────────────────────────────────────────────────────

/**
 * Send a message in a mentor workspace.
 */
export async function sendMessage(
  params: {
    workspaceId: string
    senderId: string
    message: string
    role: 'MENTOR_ROLE' | 'APPLICANT_ROLE' | 'ADMIN_ROLE'
  },
  prisma: PrismaClient,
) {
  const assignment = await prisma.mentorAssignment.findUnique({
    where: { id: params.workspaceId },
  })

  if (!assignment) {
    throw new Error('Mentor assignment not found')
  }

  if (!assignment.workspaceEnabled) {
    throw new Error('Workspace is not enabled for this assignment')
  }

  return prisma.mentorMessage.create({
    data: {
      workspaceId: params.workspaceId,
      projectId: assignment.projectId,
      senderId: params.senderId,
      message: params.message,
      senderRole: params.role,
    },
    include: {
      sender: { select: { id: true, name: true, email: true } },
    },
  })
}

/**
 * Get messages for a workspace.
 */
export async function getMessages(
  workspaceId: string,
  prisma: PrismaClient,
) {
  return prisma.mentorMessage.findMany({
    where: { workspaceId },
    include: {
      sender: { select: { id: true, name: true, email: true, role: true } },
    },
    orderBy: { createdAt: 'asc' },
  })
}

/**
 * Mark a message as read.
 */
export async function markRead(
  messageId: string,
  prisma: PrismaClient,
): Promise<void> {
  await prisma.mentorMessage.update({
    where: { id: messageId },
    data: { isRead: true },
  })
}

// ─── File Management ────────────────────────────────────────────────────────

/**
 * Record a file upload in a workspace.
 *
 * `workspaceId` is the originating MentorAssignment id (kept on the row as an
 * audit-trail FK). We derive the project id from that assignment so the file
 * is bound to the project — meaning any co-mentor on the project can see/use
 * it, and the row survives if this particular assignment is later dropped.
 */
export async function uploadFile(
  params: {
    workspaceId: string
    uploadedByUserId: string
    fileName: string
    mimeType: string
    size: number
    bucket: string
    objectKey: string
    description?: string
  },
  prisma: PrismaClient,
) {
  const assignment = await prisma.mentorAssignment.findUnique({
    where: { id: params.workspaceId },
  })

  if (!assignment) {
    throw new Error('Mentor assignment not found')
  }

  if (!assignment.workspaceEnabled) {
    throw new Error('Workspace is not enabled for this assignment')
  }

  return prisma.mentorFile.create({
    data: {
      projectId: assignment.projectId,
      mentorAssignmentId: params.workspaceId,
      uploadedByUserId: params.uploadedByUserId,
      fileName: params.fileName,
      mimeType: params.mimeType,
      size: params.size,
      bucket: params.bucket,
      objectKey: params.objectKey,
      description: params.description,
    },
    include: {
      uploadedBy: { select: { id: true, name: true, email: true } },
    },
  })
}

/**
 * Add a comment to a file.
 */
export async function addFileComment(
  params: {
    mentorFileId: string
    authorId: string
    content: string
    parentCommentId?: string
  },
  prisma: PrismaClient,
) {
  return prisma.mentorFileComment.create({
    data: {
      mentorFileId: params.mentorFileId,
      authorId: params.authorId,
      content: params.content,
      parentCommentId: params.parentCommentId,
    },
    include: {
      author: { select: { id: true, name: true, email: true } },
    },
  })
}

// ─── File Promotion ─────────────────────────────────────────────────────────

/**
 * Promote a mentor file to an official submission.
 * Creates SubmissionPromotionEvent and marks MentorFile.isPromoted = true.
 */
export async function promoteFile(
  params: {
    mentorFileId: string
    roundId: string
    slotKey: string
    promotedById: string
  },
  prisma: PrismaClient,
): Promise<{ success: boolean; errors?: string[] }> {
  try {
    const file = await prisma.mentorFile.findUnique({
      where: { id: params.mentorFileId },
    })

    if (!file) {
      return { success: false, errors: ['Mentor file not found'] }
    }

    if (file.isPromoted) {
      return { success: false, errors: ['File is already promoted'] }
    }

    await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
      // Mark file as promoted
      await tx.mentorFile.update({
        where: { id: params.mentorFileId },
        data: {
          isPromoted: true,
          promotedAt: new Date(),
          promotedByUserId: params.promotedById,
        },
      })

      // Create promotion event
      await tx.submissionPromotionEvent.create({
        data: {
          projectId: file.projectId,
          roundId: params.roundId,
          slotKey: params.slotKey,
          sourceType: 'MENTOR_FILE',
          sourceFileId: params.mentorFileId,
          promotedById: params.promotedById,
        },
      })

      await tx.decisionAuditLog.create({
        data: {
          eventType: 'mentor_file.promoted',
          entityType: 'MentorFile',
          entityId: params.mentorFileId,
          actorId: params.promotedById,
          detailsJson: {
            projectId: file.projectId,
            roundId: params.roundId,
            slotKey: params.slotKey,
            fileName: file.fileName,
          },
          snapshotJson: { timestamp: new Date().toISOString(), emittedBy: 'mentor-workspace' },
        },
      })

      await logAudit({
        prisma: tx,
        userId: params.promotedById,
        action: 'MENTOR_FILE_PROMOTE',
        entityType: 'MentorFile',
        entityId: params.mentorFileId,
        detailsJson: {
          projectId: file.projectId,
          slotKey: params.slotKey,
        },
      })
    })

    return { success: true }
  } catch (error) {
    console.error('[MentorWorkspace] promoteFile failed:', error)
    return {
      success: false,
      errors: [error instanceof Error ? error.message : 'Unknown error'],
    }
  }
}

/**
 * List files for a project, newest first, with comment counts and uploader.
 * Project-scoped: every mentor assigned to the project (and every team member)
 * sees the same file list, even if some files were uploaded under a now-dropped
 * assignment.
 */
export async function getFiles(
  projectId: string,
  prisma: PrismaClient,
) {
  return prisma.mentorFile.findMany({
    where: { projectId },
    orderBy: { createdAt: 'desc' },
    include: {
      uploadedBy: { select: { id: true, name: true, email: true } },
      _count: { select: { comments: true } },
    },
  })
}

/**
 * Delete a file. Caller must be either the uploader, OR any mentor currently
 * assigned (not dropped) to the file's project, OR a team member of the
 * file's project. Removes the MinIO object and the DB row + cascade-deletes
 * comments.
 */
export async function deleteFile(
  params: { mentorFileId: string; userId: string },
  prisma: PrismaClient,
  removeStorageObject: (bucket: string, key: string) => Promise<void>,
): Promise<void> {
  const file = await prisma.mentorFile.findUnique({
    where: { id: params.mentorFileId },
  })
  if (!file) throw new Error('File not found')
  const isUploader = file.uploadedByUserId === params.userId
  let isAuthorized = isUploader
  if (!isAuthorized) {
    const mentorAssignment = await prisma.mentorAssignment.findFirst({
      where: { projectId: file.projectId, mentorId: params.userId, droppedAt: null },
      select: { id: true },
    })
    if (mentorAssignment) {
      isAuthorized = true
    }
  }
  if (!isAuthorized) {
    const teamMembership = await prisma.teamMember.findFirst({
      where: { projectId: file.projectId, userId: params.userId },
      select: { id: true },
    })
    if (teamMembership) {
      isAuthorized = true
    }
  }
  if (!isAuthorized) {
    throw new Error('Only the uploader, an assigned mentor, or a team member can delete this file')
  }
  try {
    await removeStorageObject(file.bucket, file.objectKey)
  } catch (err) {
    console.error('[mentor-workspace] failed to delete storage object', file.objectKey, err)
  }
  await prisma.mentorFile.delete({ where: { id: params.mentorFileId } })
}
