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'

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
      const enrichedSuggestions = await Promise.all(
        suggestions.map(async (suggestion) => {
          const mentor = await ctx.prisma.user.findUnique({
            where: { id: suggestion.mentorId },
            select: {
              id: true,
              name: true,
              email: true,
              expertiseTags: true,
              mentorAssignments: {
                select: { id: true },
              },
            },
          })

          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
      const assignment = await ctx.prisma.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,
            },
          },
        },
      })

      // Create audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'MENTOR_ASSIGN',
          entityType: 'MentorAssignment',
          entityId: assignment.id,
          detailsJson: {
            projectId: input.projectId,
            projectTitle: assignment.project.title,
            mentorId: input.mentorId,
            mentorName: assignment.mentor.name,
            method: input.method,
          },
          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: 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 ctx.prisma.auditLog.create({
        data: {
          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',
        })
      }

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

      // Create audit log
      await ctx.prisma.auditLog.create({
        data: {
          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,
        },
      })

      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 ctx.prisma.auditLog.create({
        data: {
          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,
      }
    }),

  /**
   * 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),
      }
    }),
})
