import { z } from 'zod'
import { TRPCError } from '@trpc/server'
import { router, mentorProcedure, adminProcedure } from '../trpc'
import { MentorAssignmentMethod } from '@prisma/client'
import {
  getAIMentorSuggestions,
  getRoundRobinMentor,
} from '../services/mentor-matching'
import {
  createNotification,
  notifyProjectTeam,
  NotificationTypes,
} from '../services/in-app-notification'
import { logAudit } from '@/server/utils/audit'

export const mentorRouter = router({
  /**
   * Get AI-suggested mentor matches for a project
   */
  getSuggestions: adminProcedure
    .input(
      z.object({
        projectId: z.string(),
        limit: z.number().min(1).max(10).default(5),
      })
    )
    .query(async ({ ctx, input }) => {
      // Verify project exists
      const project = await ctx.prisma.project.findUniqueOrThrow({
        where: { id: input.projectId },
        include: {
          mentorAssignment: true,
        },
      })

      if (project.mentorAssignment) {
        return {
          currentMentor: project.mentorAssignment,
          suggestions: [],
          message: 'Project already has a mentor assigned',
        }
      }

      const suggestions = await getAIMentorSuggestions(
        ctx.prisma,
        input.projectId,
        input.limit
      )

      // Enrich with mentor details (batch query to avoid N+1)
      const mentorIds = suggestions.map((s) => s.mentorId)
      const mentors = await ctx.prisma.user.findMany({
        where: { id: { in: mentorIds } },
        select: {
          id: true,
          name: true,
          email: true,
          expertiseTags: true,
          mentorAssignments: {
            select: { id: true },
          },
        },
      })
      const mentorMap = new Map(mentors.map((m) => [m.id, m]))

      const enrichedSuggestions = suggestions.map((suggestion) => {
        const mentor = mentorMap.get(suggestion.mentorId)
        return {
          ...suggestion,
          mentor: mentor
            ? {
                id: mentor.id,
                name: mentor.name,
                email: mentor.email,
                expertiseTags: mentor.expertiseTags,
                assignmentCount: mentor.mentorAssignments.length,
              }
            : null,
        }
      })

      return {
        currentMentor: null,
        suggestions: enrichedSuggestions.filter((s) => s.mentor !== null),
        message: null,
      }
    }),

  /**
   * Manually assign a mentor to a project
   */
  assign: adminProcedure
    .input(
      z.object({
        projectId: z.string(),
        mentorId: z.string(),
        method: z.nativeEnum(MentorAssignmentMethod).default('MANUAL'),
        aiConfidenceScore: z.number().optional(),
        expertiseMatchScore: z.number().optional(),
        aiReasoning: z.string().optional(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      // Verify project exists and doesn't have a mentor
      const project = await ctx.prisma.project.findUniqueOrThrow({
        where: { id: input.projectId },
        include: { mentorAssignment: true },
      })

      if (project.mentorAssignment) {
        throw new TRPCError({
          code: 'CONFLICT',
          message: 'Project already has a mentor assigned',
        })
      }

      // Verify mentor exists
      const mentor = await ctx.prisma.user.findUniqueOrThrow({
        where: { id: input.mentorId },
      })

      // Create assignment + audit log in transaction
      const assignment = await ctx.prisma.$transaction(async (tx) => {
        const created = await tx.mentorAssignment.create({
          data: {
            projectId: input.projectId,
            mentorId: input.mentorId,
            method: input.method,
            assignedBy: ctx.user.id,
            aiConfidenceScore: input.aiConfidenceScore,
            expertiseMatchScore: input.expertiseMatchScore,
            aiReasoning: input.aiReasoning,
          },
          include: {
            mentor: {
              select: {
                id: true,
                name: true,
                email: true,
                expertiseTags: true,
              },
            },
            project: {
              select: {
                id: true,
                title: true,
              },
            },
          },
        })

        await logAudit({
          prisma: tx,
          userId: ctx.user.id,
          action: 'MENTOR_ASSIGN',
          entityType: 'MentorAssignment',
          entityId: created.id,
          detailsJson: {
            projectId: input.projectId,
            projectTitle: created.project.title,
            mentorId: input.mentorId,
            mentorName: created.mentor.name,
            method: input.method,
          },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        })

        return created
      })

      // Get team lead info for mentor notification
      const teamLead = await ctx.prisma.teamMember.findFirst({
        where: { projectId: input.projectId, role: 'LEAD' },
        include: { user: { select: { name: true, email: true } } },
      })

      // Notify mentor of new mentee
      await createNotification({
        userId: input.mentorId,
        type: NotificationTypes.MENTEE_ASSIGNED,
        title: 'New Mentee Assigned',
        message: `You have been assigned to mentor "${assignment.project.title}".`,
        linkUrl: `/mentor/projects/${input.projectId}`,
        linkLabel: 'View Project',
        priority: 'high',
        metadata: {
          projectName: assignment.project.title,
          teamLeadName: teamLead?.user?.name || 'Team Lead',
          teamLeadEmail: teamLead?.user?.email,
        },
      })

      // Notify project team of mentor assignment
      await notifyProjectTeam(input.projectId, {
        type: NotificationTypes.MENTOR_ASSIGNED,
        title: 'Mentor Assigned',
        message: `${assignment.mentor.name || 'A mentor'} has been assigned to support your project.`,
        linkUrl: `/team/projects/${input.projectId}`,
        linkLabel: 'View Project',
        priority: 'high',
        metadata: {
          projectName: assignment.project.title,
          mentorName: assignment.mentor.name,
        },
      })

      return assignment
    }),

  /**
   * Auto-assign a mentor using AI or round-robin
   */
  autoAssign: adminProcedure
    .input(
      z.object({
        projectId: z.string(),
        useAI: z.boolean().default(true),
      })
    )
    .mutation(async ({ ctx, input }) => {
      // Verify project exists and doesn't have a mentor
      const project = await ctx.prisma.project.findUniqueOrThrow({
        where: { id: input.projectId },
        include: { mentorAssignment: true },
      })

      if (project.mentorAssignment) {
        throw new TRPCError({
          code: 'CONFLICT',
          message: 'Project already has a mentor assigned',
        })
      }

      let mentorId: string | null = null
      let method: MentorAssignmentMethod = 'ALGORITHM'
      let aiConfidenceScore: number | undefined
      let expertiseMatchScore: number | undefined
      let aiReasoning: string | undefined

      if (input.useAI) {
        // Try AI matching first
        const suggestions = await getAIMentorSuggestions(ctx.prisma, input.projectId, 1)

        if (suggestions.length > 0) {
          const best = suggestions[0]
          mentorId = best.mentorId
          method = 'AI_AUTO'
          aiConfidenceScore = best.confidenceScore
          expertiseMatchScore = best.expertiseMatchScore
          aiReasoning = best.reasoning
        }
      }

      // Fallback to round-robin
      if (!mentorId) {
        mentorId = await getRoundRobinMentor(ctx.prisma)
        method = 'ALGORITHM'
      }

      if (!mentorId) {
        throw new TRPCError({
          code: 'NOT_FOUND',
          message: 'No available mentors found',
        })
      }

      // Create assignment
      const assignment = await ctx.prisma.mentorAssignment.create({
        data: {
          projectId: input.projectId,
          mentorId,
          method,
          assignedBy: ctx.user.id,
          aiConfidenceScore,
          expertiseMatchScore,
          aiReasoning,
        },
        include: {
          mentor: {
            select: {
              id: true,
              name: true,
              email: true,
              expertiseTags: true,
            },
          },
          project: {
            select: {
              id: true,
              title: true,
            },
          },
        },
      })

      // Create audit log
      await logAudit({
        prisma: ctx.prisma,
        userId: ctx.user.id,
        action: 'MENTOR_AUTO_ASSIGN',
        entityType: 'MentorAssignment',
        entityId: assignment.id,
        detailsJson: {
          projectId: input.projectId,
          projectTitle: assignment.project.title,
          mentorId,
          mentorName: assignment.mentor.name,
          method,
          aiConfidenceScore,
        },
        ipAddress: ctx.ip,
        userAgent: ctx.userAgent,
      })

      // Get team lead info for mentor notification
      const teamLead = await ctx.prisma.teamMember.findFirst({
        where: { projectId: input.projectId, role: 'LEAD' },
        include: { user: { select: { name: true, email: true } } },
      })

      // Notify mentor of new mentee
      await createNotification({
        userId: mentorId,
        type: NotificationTypes.MENTEE_ASSIGNED,
        title: 'New Mentee Assigned',
        message: `You have been assigned to mentor "${assignment.project.title}".`,
        linkUrl: `/mentor/projects/${input.projectId}`,
        linkLabel: 'View Project',
        priority: 'high',
        metadata: {
          projectName: assignment.project.title,
          teamLeadName: teamLead?.user?.name || 'Team Lead',
          teamLeadEmail: teamLead?.user?.email,
        },
      })

      // Notify project team of mentor assignment
      await notifyProjectTeam(input.projectId, {
        type: NotificationTypes.MENTOR_ASSIGNED,
        title: 'Mentor Assigned',
        message: `${assignment.mentor.name || 'A mentor'} has been assigned to support your project.`,
        linkUrl: `/team/projects/${input.projectId}`,
        linkLabel: 'View Project',
        priority: 'high',
        metadata: {
          projectName: assignment.project.title,
          mentorName: assignment.mentor.name,
        },
      })

      return assignment
    }),

  /**
   * Remove mentor assignment
   */
  unassign: adminProcedure
    .input(z.object({ projectId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const assignment = await ctx.prisma.mentorAssignment.findUnique({
        where: { projectId: input.projectId },
        include: {
          mentor: { select: { id: true, name: true } },
          project: { select: { id: true, title: true } },
        },
      })

      if (!assignment) {
        throw new TRPCError({
          code: 'NOT_FOUND',
          message: 'No mentor assignment found for this project',
        })
      }

      // Delete assignment + audit log in transaction
      await ctx.prisma.$transaction(async (tx) => {
        await logAudit({
          prisma: tx,
          userId: ctx.user.id,
          action: 'MENTOR_UNASSIGN',
          entityType: 'MentorAssignment',
          entityId: assignment.id,
          detailsJson: {
            projectId: input.projectId,
            projectTitle: assignment.project.title,
            mentorId: assignment.mentor.id,
            mentorName: assignment.mentor.name,
          },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        })

        await tx.mentorAssignment.delete({
          where: { projectId: input.projectId },
        })
      })

      return { success: true }
    }),

  /**
   * Bulk auto-assign mentors to projects without one
   */
  bulkAutoAssign: adminProcedure
    .input(
      z.object({
        roundId: z.string(),
        useAI: z.boolean().default(true),
        maxAssignments: z.number().min(1).max(100).default(50),
      })
    )
    .mutation(async ({ ctx, input }) => {
      // Get projects without mentors
      const projects = await ctx.prisma.project.findMany({
        where: {
          roundId: input.roundId,
          mentorAssignment: null,
          wantsMentorship: true,
        },
        select: { id: true },
        take: input.maxAssignments,
      })

      if (projects.length === 0) {
        return {
          assigned: 0,
          failed: 0,
          message: 'No projects need mentor assignment',
        }
      }

      let assigned = 0
      let failed = 0

      for (const project of projects) {
        try {
          let mentorId: string | null = null
          let method: MentorAssignmentMethod = 'ALGORITHM'
          let aiConfidenceScore: number | undefined
          let expertiseMatchScore: number | undefined
          let aiReasoning: string | undefined

          if (input.useAI) {
            const suggestions = await getAIMentorSuggestions(ctx.prisma, project.id, 1)
            if (suggestions.length > 0) {
              const best = suggestions[0]
              mentorId = best.mentorId
              method = 'AI_AUTO'
              aiConfidenceScore = best.confidenceScore
              expertiseMatchScore = best.expertiseMatchScore
              aiReasoning = best.reasoning
            }
          }

          if (!mentorId) {
            mentorId = await getRoundRobinMentor(ctx.prisma)
            method = 'ALGORITHM'
          }

          if (mentorId) {
            const assignment = await ctx.prisma.mentorAssignment.create({
              data: {
                projectId: project.id,
                mentorId,
                method,
                assignedBy: ctx.user.id,
                aiConfidenceScore,
                expertiseMatchScore,
                aiReasoning,
              },
              include: {
                mentor: { select: { name: true } },
                project: { select: { title: true } },
              },
            })

            // Get team lead info
            const teamLead = await ctx.prisma.teamMember.findFirst({
              where: { projectId: project.id, role: 'LEAD' },
              include: { user: { select: { name: true, email: true } } },
            })

            // Notify mentor
            await createNotification({
              userId: mentorId,
              type: NotificationTypes.MENTEE_ASSIGNED,
              title: 'New Mentee Assigned',
              message: `You have been assigned to mentor "${assignment.project.title}".`,
              linkUrl: `/mentor/projects/${project.id}`,
              linkLabel: 'View Project',
              priority: 'high',
              metadata: {
                projectName: assignment.project.title,
                teamLeadName: teamLead?.user?.name || 'Team Lead',
                teamLeadEmail: teamLead?.user?.email,
              },
            })

            // Notify project team
            await notifyProjectTeam(project.id, {
              type: NotificationTypes.MENTOR_ASSIGNED,
              title: 'Mentor Assigned',
              message: `${assignment.mentor.name || 'A mentor'} has been assigned to support your project.`,
              linkUrl: `/team/projects/${project.id}`,
              linkLabel: 'View Project',
              priority: 'high',
              metadata: {
                projectName: assignment.project.title,
                mentorName: assignment.mentor.name,
              },
            })

            assigned++
          } else {
            failed++
          }
        } catch {
          failed++
        }
      }

      // Create audit log
      await logAudit({
        prisma: ctx.prisma,
        userId: ctx.user.id,
        action: 'MENTOR_BULK_ASSIGN',
        entityType: 'Round',
        entityId: input.roundId,
        detailsJson: {
          assigned,
          failed,
          useAI: input.useAI,
        },
        ipAddress: ctx.ip,
        userAgent: ctx.userAgent,
      })

      return {
        assigned,
        failed,
        message: `Assigned ${assigned} mentor(s), ${failed} failed`,
      }
    }),

  /**
   * Get mentor's assigned projects
   */
  getMyProjects: mentorProcedure.query(async ({ ctx }) => {
    const assignments = await ctx.prisma.mentorAssignment.findMany({
      where: { mentorId: ctx.user.id },
      include: {
        project: {
          include: {
            round: {
              include: {
                program: { select: { name: true, year: true } },
              },
            },
            teamMembers: {
              include: {
                user: { select: { id: true, name: true, email: true } },
              },
            },
          },
        },
      },
      orderBy: { assignedAt: 'desc' },
    })

    return assignments
  }),

  /**
   * Get detailed project info for a mentor's assigned project
   */
  getProjectDetail: mentorProcedure
    .input(z.object({ projectId: z.string() }))
    .query(async ({ ctx, input }) => {
      // Verify the mentor is assigned to this project
      const assignment = await ctx.prisma.mentorAssignment.findFirst({
        where: {
          projectId: input.projectId,
          mentorId: ctx.user.id,
        },
      })

      // Allow admins to access any project
      const isAdmin = ['SUPER_ADMIN', 'PROGRAM_ADMIN'].includes(ctx.user.role)

      if (!assignment && !isAdmin) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You are not assigned to mentor this project',
        })
      }

      const project = await ctx.prisma.project.findUniqueOrThrow({
        where: { id: input.projectId },
        include: {
          round: {
            include: {
              program: { select: { id: true, name: true, year: true } },
            },
          },
          teamMembers: {
            include: {
              user: {
                select: {
                  id: true,
                  name: true,
                  email: true,
                  phoneNumber: true,
                },
              },
            },
            orderBy: { role: 'asc' },
          },
          files: {
            orderBy: { createdAt: 'desc' },
          },
          mentorAssignment: {
            include: {
              mentor: {
                select: { id: true, name: true, email: true },
              },
            },
          },
        },
      })

      return {
        ...project,
        assignedAt: assignment?.assignedAt,
      }
    }),

  /**
   * Send a message to the project team (mentor side)
   */
  sendMessage: mentorProcedure
    .input(
      z.object({
        projectId: z.string(),
        message: z.string().min(1).max(5000),
      })
    )
    .mutation(async ({ ctx, input }) => {
      // Verify the mentor is assigned to this project
      const assignment = await ctx.prisma.mentorAssignment.findFirst({
        where: {
          projectId: input.projectId,
          mentorId: ctx.user.id,
        },
      })

      const isAdmin = ['SUPER_ADMIN', 'PROGRAM_ADMIN'].includes(ctx.user.role)

      if (!assignment && !isAdmin) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You are not assigned to mentor this project',
        })
      }

      const mentorMessage = await ctx.prisma.mentorMessage.create({
        data: {
          projectId: input.projectId,
          senderId: ctx.user.id,
          message: input.message,
        },
        include: {
          sender: {
            select: { id: true, name: true, email: true },
          },
        },
      })

      // Notify project team members
      await notifyProjectTeam(input.projectId, {
        type: 'MENTOR_MESSAGE',
        title: 'New Message from Mentor',
        message: `${ctx.user.name || 'Your mentor'} sent you a message`,
        linkUrl: `/my-submission/${input.projectId}`,
        linkLabel: 'View Message',
        priority: 'normal',
        metadata: {
          projectId: input.projectId,
        },
      })

      return mentorMessage
    }),

  /**
   * Get messages for a project (mentor side)
   */
  getMessages: mentorProcedure
    .input(z.object({ projectId: z.string() }))
    .query(async ({ ctx, input }) => {
      // Verify the mentor is assigned to this project
      const assignment = await ctx.prisma.mentorAssignment.findFirst({
        where: {
          projectId: input.projectId,
          mentorId: ctx.user.id,
        },
      })

      const isAdmin = ['SUPER_ADMIN', 'PROGRAM_ADMIN'].includes(ctx.user.role)

      if (!assignment && !isAdmin) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You are not assigned to mentor this project',
        })
      }

      const messages = await ctx.prisma.mentorMessage.findMany({
        where: { projectId: input.projectId },
        include: {
          sender: {
            select: { id: true, name: true, email: true, role: true },
          },
        },
        orderBy: { createdAt: 'asc' },
      })

      // Mark unread messages from the team as read
      await ctx.prisma.mentorMessage.updateMany({
        where: {
          projectId: input.projectId,
          senderId: { not: ctx.user.id },
          isRead: false,
        },
        data: { isRead: true },
      })

      return messages
    }),

  /**
   * List all mentor assignments (admin)
   */
  listAssignments: adminProcedure
    .input(
      z.object({
        roundId: z.string().optional(),
        mentorId: z.string().optional(),
        page: z.number().min(1).default(1),
        perPage: z.number().min(1).max(100).default(20),
      })
    )
    .query(async ({ ctx, input }) => {
      const where = {
        ...(input.roundId && { project: { roundId: input.roundId } }),
        ...(input.mentorId && { mentorId: input.mentorId }),
      }

      const [assignments, total] = await Promise.all([
        ctx.prisma.mentorAssignment.findMany({
          where,
          include: {
            project: {
              select: {
                id: true,
                title: true,
                teamName: true,
                oceanIssue: true,
                competitionCategory: true,
                status: true,
              },
            },
            mentor: {
              select: {
                id: true,
                name: true,
                email: true,
                expertiseTags: true,
              },
            },
          },
          orderBy: { assignedAt: 'desc' },
          skip: (input.page - 1) * input.perPage,
          take: input.perPage,
        }),
        ctx.prisma.mentorAssignment.count({ where }),
      ])

      return {
        assignments,
        total,
        page: input.page,
        perPage: input.perPage,
        totalPages: Math.ceil(total / input.perPage),
      }
    }),

  // =========================================================================
  // Mentor Notes CRUD (F8)
  // =========================================================================

  /**
   * Create a mentor note for an assignment
   */
  createNote: mentorProcedure
    .input(
      z.object({
        mentorAssignmentId: z.string(),
        content: z.string().min(1).max(10000),
        isVisibleToAdmin: z.boolean().default(true),
      })
    )
    .mutation(async ({ ctx, input }) => {
      // Verify the user owns this assignment or is admin
      const assignment = await ctx.prisma.mentorAssignment.findUniqueOrThrow({
        where: { id: input.mentorAssignmentId },
        select: { mentorId: true, projectId: true },
      })

      const isAdmin = ['SUPER_ADMIN', 'PROGRAM_ADMIN'].includes(ctx.user.role)
      if (assignment.mentorId !== ctx.user.id && !isAdmin) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You are not assigned to this mentorship',
        })
      }

      const note = await ctx.prisma.mentorNote.create({
        data: {
          mentorAssignmentId: input.mentorAssignmentId,
          authorId: ctx.user.id,
          content: input.content,
          isVisibleToAdmin: input.isVisibleToAdmin,
        },
        include: {
          author: { select: { id: true, name: true, email: true } },
        },
      })

      try {
        await logAudit({
          prisma: ctx.prisma,
          userId: ctx.user.id,
          action: 'CREATE_MENTOR_NOTE',
          entityType: 'MentorNote',
          entityId: note.id,
          detailsJson: {
            mentorAssignmentId: input.mentorAssignmentId,
            projectId: assignment.projectId,
          },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        })
      } catch {
        // Audit log errors should never break the operation
      }

      return note
    }),

  /**
   * Update a mentor note
   */
  updateNote: mentorProcedure
    .input(
      z.object({
        noteId: z.string(),
        content: z.string().min(1).max(10000),
        isVisibleToAdmin: z.boolean().optional(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const note = await ctx.prisma.mentorNote.findUniqueOrThrow({
        where: { id: input.noteId },
        select: { authorId: true },
      })

      if (note.authorId !== ctx.user.id) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You can only edit your own notes',
        })
      }

      return ctx.prisma.mentorNote.update({
        where: { id: input.noteId },
        data: {
          content: input.content,
          ...(input.isVisibleToAdmin !== undefined && { isVisibleToAdmin: input.isVisibleToAdmin }),
        },
        include: {
          author: { select: { id: true, name: true, email: true } },
        },
      })
    }),

  /**
   * Delete a mentor note
   */
  deleteNote: mentorProcedure
    .input(z.object({ noteId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const note = await ctx.prisma.mentorNote.findUniqueOrThrow({
        where: { id: input.noteId },
        select: { authorId: true },
      })

      if (note.authorId !== ctx.user.id) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You can only delete your own notes',
        })
      }

      return ctx.prisma.mentorNote.delete({
        where: { id: input.noteId },
      })
    }),

  /**
   * Get notes for a mentor assignment
   */
  getNotes: mentorProcedure
    .input(z.object({ mentorAssignmentId: z.string() }))
    .query(async ({ ctx, input }) => {
      const assignment = await ctx.prisma.mentorAssignment.findUniqueOrThrow({
        where: { id: input.mentorAssignmentId },
        select: { mentorId: true },
      })

      const isAdmin = ['SUPER_ADMIN', 'PROGRAM_ADMIN'].includes(ctx.user.role)

      if (assignment.mentorId !== ctx.user.id && !isAdmin) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You are not assigned to this mentorship',
        })
      }

      // Admins see all notes; mentors see only their own
      const where: Record<string, unknown> = { mentorAssignmentId: input.mentorAssignmentId }
      if (!isAdmin) {
        where.authorId = ctx.user.id
      }

      return ctx.prisma.mentorNote.findMany({
        where,
        include: {
          author: { select: { id: true, name: true, email: true } },
        },
        orderBy: { createdAt: 'desc' },
      })
    }),

  // =========================================================================
  // Milestone Operations (F8)
  // =========================================================================

  /**
   * Get milestones for a program with completion status
   */
  getMilestones: mentorProcedure
    .input(z.object({ programId: z.string() }))
    .query(async ({ ctx, input }) => {
      const milestones = await ctx.prisma.mentorMilestone.findMany({
        where: { programId: input.programId },
        include: {
          completions: {
            include: {
              mentorAssignment: { select: { id: true, projectId: true } },
            },
          },
        },
        orderBy: { sortOrder: 'asc' },
      })

      // Get current user's assignments for completion status context
      const myAssignments = await ctx.prisma.mentorAssignment.findMany({
        where: { mentorId: ctx.user.id },
        select: { id: true, projectId: true },
      })
      const myAssignmentIds = new Set(myAssignments.map((a) => a.id))

      return milestones.map((milestone) => ({
        ...milestone,
        myCompletions: milestone.completions.filter((c) =>
          myAssignmentIds.has(c.mentorAssignmentId)
        ),
      }))
    }),

  /**
   * Mark a milestone as completed for an assignment
   */
  completeMilestone: mentorProcedure
    .input(
      z.object({
        milestoneId: z.string(),
        mentorAssignmentId: z.string(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      // Verify the user owns this assignment
      const assignment = await ctx.prisma.mentorAssignment.findUniqueOrThrow({
        where: { id: input.mentorAssignmentId },
        select: { mentorId: true, projectId: true },
      })

      const isAdmin = ['SUPER_ADMIN', 'PROGRAM_ADMIN'].includes(ctx.user.role)
      if (assignment.mentorId !== ctx.user.id && !isAdmin) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You are not assigned to this mentorship',
        })
      }

      const completion = await ctx.prisma.mentorMilestoneCompletion.create({
        data: {
          milestoneId: input.milestoneId,
          mentorAssignmentId: input.mentorAssignmentId,
          completedById: ctx.user.id,
        },
      })

      // Check if all required milestones are now completed
      const milestone = await ctx.prisma.mentorMilestone.findUniqueOrThrow({
        where: { id: input.milestoneId },
        select: { programId: true },
      })

      const requiredMilestones = await ctx.prisma.mentorMilestone.findMany({
        where: { programId: milestone.programId, isRequired: true },
        select: { id: true },
      })

      const completedMilestones = await ctx.prisma.mentorMilestoneCompletion.findMany({
        where: {
          mentorAssignmentId: input.mentorAssignmentId,
          milestoneId: { in: requiredMilestones.map((m) => m.id) },
        },
        select: { milestoneId: true },
      })

      const allRequiredDone = requiredMilestones.length > 0 &&
        completedMilestones.length >= requiredMilestones.length

      if (allRequiredDone) {
        await ctx.prisma.mentorAssignment.update({
          where: { id: input.mentorAssignmentId },
          data: { completionStatus: 'completed' },
        })
      }

      try {
        await logAudit({
          prisma: ctx.prisma,
          userId: ctx.user.id,
          action: 'COMPLETE_MILESTONE',
          entityType: 'MentorMilestoneCompletion',
          entityId: completion.id,
          detailsJson: {
            milestoneId: input.milestoneId,
            mentorAssignmentId: input.mentorAssignmentId,
            allRequiredDone,
          },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        })
      } catch {
        // Audit log errors should never break the operation
      }

      return { completion, allRequiredDone }
    }),

  /**
   * Uncomplete a milestone for an assignment
   */
  uncompleteMilestone: mentorProcedure
    .input(
      z.object({
        milestoneId: z.string(),
        mentorAssignmentId: z.string(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const assignment = await ctx.prisma.mentorAssignment.findUniqueOrThrow({
        where: { id: input.mentorAssignmentId },
        select: { mentorId: true },
      })

      const isAdmin = ['SUPER_ADMIN', 'PROGRAM_ADMIN'].includes(ctx.user.role)
      if (assignment.mentorId !== ctx.user.id && !isAdmin) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You are not assigned to this mentorship',
        })
      }

      await ctx.prisma.mentorMilestoneCompletion.delete({
        where: {
          milestoneId_mentorAssignmentId: {
            milestoneId: input.milestoneId,
            mentorAssignmentId: input.mentorAssignmentId,
          },
        },
      })

      // Revert completion status if it was completed
      await ctx.prisma.mentorAssignment.update({
        where: { id: input.mentorAssignmentId },
        data: { completionStatus: 'in_progress' },
      })

      return { success: true }
    }),

  // =========================================================================
  // Admin Milestone Management (F8)
  // =========================================================================

  /**
   * Create a milestone for a program
   */
  createMilestone: adminProcedure
    .input(
      z.object({
        programId: z.string(),
        name: z.string().min(1).max(255),
        description: z.string().max(2000).optional(),
        isRequired: z.boolean().default(false),
        deadlineOffsetDays: z.number().int().optional().nullable(),
        sortOrder: z.number().int().default(0),
      })
    )
    .mutation(async ({ ctx, input }) => {
      return ctx.prisma.mentorMilestone.create({
        data: input,
      })
    }),

  /**
   * Update a milestone
   */
  updateMilestone: adminProcedure
    .input(
      z.object({
        milestoneId: z.string(),
        name: z.string().min(1).max(255).optional(),
        description: z.string().max(2000).optional().nullable(),
        isRequired: z.boolean().optional(),
        deadlineOffsetDays: z.number().int().optional().nullable(),
        sortOrder: z.number().int().optional(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const { milestoneId, ...data } = input
      return ctx.prisma.mentorMilestone.update({
        where: { id: milestoneId },
        data,
      })
    }),

  /**
   * Delete a milestone (cascades completions)
   */
  deleteMilestone: adminProcedure
    .input(z.object({ milestoneId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      return ctx.prisma.mentorMilestone.delete({
        where: { id: input.milestoneId },
      })
    }),

  /**
   * Reorder milestones
   */
  reorderMilestones: adminProcedure
    .input(
      z.object({
        milestoneIds: z.array(z.string()),
      })
    )
    .mutation(async ({ ctx, input }) => {
      await ctx.prisma.$transaction(
        input.milestoneIds.map((id, index) =>
          ctx.prisma.mentorMilestone.update({
            where: { id },
            data: { sortOrder: index },
          })
        )
      )

      return { success: true }
    }),

  // =========================================================================
  // Activity Tracking (F8)
  // =========================================================================

  /**
   * Track a mentor's view of an assignment
   */
  trackView: mentorProcedure
    .input(z.object({ mentorAssignmentId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const assignment = await ctx.prisma.mentorAssignment.findUniqueOrThrow({
        where: { id: input.mentorAssignmentId },
        select: { mentorId: true },
      })

      const isAdmin = ['SUPER_ADMIN', 'PROGRAM_ADMIN'].includes(ctx.user.role)
      if (assignment.mentorId !== ctx.user.id && !isAdmin) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'You are not assigned to this mentorship',
        })
      }

      return ctx.prisma.mentorAssignment.update({
        where: { id: input.mentorAssignmentId },
        data: { lastViewedAt: new Date() },
      })
    }),

  /**
   * Get activity stats for all mentors (admin)
   */
  getActivityStats: adminProcedure
    .input(
      z.object({
        roundId: z.string().optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const where = input.roundId
        ? { project: { roundId: input.roundId } }
        : {}

      const assignments = await ctx.prisma.mentorAssignment.findMany({
        where,
        include: {
          mentor: { select: { id: true, name: true, email: true } },
          project: { select: { id: true, title: true } },
          notes: { select: { id: true } },
          milestoneCompletions: { select: { id: true } },
        },
      })

      // Get message counts per mentor
      const mentorIds = [...new Set(assignments.map((a) => a.mentorId))]
      const messageCounts = await ctx.prisma.mentorMessage.groupBy({
        by: ['senderId'],
        where: { senderId: { in: mentorIds } },
        _count: true,
      })
      const messageCountMap = new Map(messageCounts.map((m) => [m.senderId, m._count]))

      // Build per-mentor stats
      const mentorStats = new Map<string, {
        mentor: { id: string; name: string | null; email: string }
        assignments: number
        lastViewedAt: Date | null
        notesCount: number
        milestonesCompleted: number
        messagesSent: number
        completionStatuses: string[]
      }>()

      for (const assignment of assignments) {
        const existing = mentorStats.get(assignment.mentorId)
        if (existing) {
          existing.assignments++
          existing.notesCount += assignment.notes.length
          existing.milestonesCompleted += assignment.milestoneCompletions.length
          existing.completionStatuses.push(assignment.completionStatus)
          if (assignment.lastViewedAt && (!existing.lastViewedAt || assignment.lastViewedAt > existing.lastViewedAt)) {
            existing.lastViewedAt = assignment.lastViewedAt
          }
        } else {
          mentorStats.set(assignment.mentorId, {
            mentor: assignment.mentor,
            assignments: 1,
            lastViewedAt: assignment.lastViewedAt,
            notesCount: assignment.notes.length,
            milestonesCompleted: assignment.milestoneCompletions.length,
            messagesSent: messageCountMap.get(assignment.mentorId) || 0,
            completionStatuses: [assignment.completionStatus],
          })
        }
      }

      return Array.from(mentorStats.values())
    }),
})
