"use server"

import * as Sentry from "@sentry/nextjs"
import { createOrUpdateUser, getUserById, prisma } from "@codeflash-ai/common"
import { Prisma } from "@prisma/client"
import { GitHubUserSearchResult, Member, UserRole } from "@/lib/types"
import { ActionResponse, createErrorResponse, createSuccessResponse } from "@/lib/action-response"
import { trackMemberInvited } from "@/lib/analytics/tracking"
import { getActionAccountContext } from "@/lib/server/get-account-context"

export async function addRepositoryMemberById(
  repoId: string,
  invitedUser: GitHubUserSearchResult,
  role: UserRole,
): Promise<ActionResponse> {
  const accountContext = await getActionAccountContext()
  if (!accountContext) {
    return createErrorResponse("Unauthorized")
  }

  const { userId: currentUserId } = accountContext

  try {
    const invitedUserId = `github|${invitedUser.githubUserId.toString()}`

    // Verify repo exists, check permissions, and check for duplicate in parallel
    // using indexed lookups instead of loading ALL members
    const [repoExists, currentUserMember, existingMember, memberCount] = await Promise.all([
      prisma.repositories.findUnique({
        where: { id: repoId },
        select: { id: true },
      }),
      prisma.repository_members.findUnique({
        where: { repository_id_user_id: { repository_id: repoId, user_id: currentUserId } },
        select: { role: true },
      }),
      prisma.repository_members.findUnique({
        where: { repository_id_user_id: { repository_id: repoId, user_id: invitedUserId } },
        select: { id: true },
      }),
      prisma.repository_members.count({
        where: { repository_id: repoId },
      }),
    ])

    if (!repoExists) {
      return createErrorResponse("Repository not found")
    }

    // Check if user has permission to add members
    const isAdmin = currentUserMember?.role === "admin" || currentUserMember?.role === "owner"
    const isOnlyMember = memberCount === 1 && currentUserMember // if only member we need to let him add because we are was not manage well the member role

    if (!isAdmin && !isOnlyMember) {
      return createErrorResponse("You don't have permission to add members")
    }

    // Check if member already exists
    if (existingMember) {
      return createErrorResponse("User is already a member of this repository")
    }

    // Check if user exists in our database by github_username
    let user = await getUserById(invitedUserId)

    // If user doesn't exist, create them with their GitHub User ID
    if (!user) {
      user = await createOrUpdateUser(invitedUserId, invitedUser.username, null, null)
    }

    let newMember
    try {
      // Add user to repository members
      newMember = await prisma.repository_members.create({
        data: {
          repository_id: repoId,
          user_id: user.user_id,
          role,
          added_by: currentUserId,
        },
      })
    } catch (error) {
      if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002") {
        return createErrorResponse("User is already a member of this repository")
      }
      throw error
    }

    trackMemberInvited(currentUserId, {
      invitedUsername: invitedUser.username,
      role,
      scope: "repository",
      targetId: repoId,
    })

    return createSuccessResponse({
      id: newMember.id,
      user_id: newMember.user_id,
      username: invitedUser.username,
      role: newMember.role,
      added_at: newMember.added_at,
      avatarUrl: invitedUser.avatarUrl,
    })
  } catch (error) {
    //Log the error for debugging purposes sentry
    Sentry.captureException("Add Repository Member failed:" + error)

    return createErrorResponse("Failed to add repository member")
  }
}

/**
 * Get repository members
 */
export async function getRepositoryMembers(repoId: string): Promise<ActionResponse<Member[]>> {
  const accountContext = await getActionAccountContext()
  if (!accountContext) {
    return createErrorResponse("Unauthorized")
  }

  const { userId: currentUserId } = accountContext

  try {
    // Check access with a single indexed lookup, then fetch members only if authorized
    const hasAccess = await prisma.repository_members.findUnique({
      where: { repository_id_user_id: { repository_id: repoId, user_id: currentUserId } },
      select: { id: true },
    })

    if (!hasAccess) {
      return createErrorResponse("You don't have access to this repository")
    }

    // Now fetch all members (only needed fields)
    const repoMembers = await prisma.repository_members.findMany({
      where: { repository_id: repoId },
      select: {
        id: true,
        user_id: true,
        role: true,
        added_at: true,
        user: { select: { github_username: true } },
      },
    })

    const members: Member[] = repoMembers.map(
      (member: {
        id: string
        user_id: string
        role: string
        added_at: Date
        user: { github_username: string }
      }) => ({
        id: member.id,
        user_id: member.user_id,
        username: member.user.github_username,
        role: member.role,
        added_at: member.added_at,
        avatarUrl: `https://github.com/${member.user.github_username}.png`,
      }),
    )

    return createSuccessResponse(members)
  } catch (error) {
    console.error("Failed to get repository members:", error)
    Sentry.captureException("Failed to get repository members:" + error)
    return createErrorResponse(error instanceof Error ? error.message : "Failed to get members")
  }
}

/**
 * Update repository member role
 */
export async function updateRepositoryMemberRole(
  repoId: string,
  memberId: string,
  newRole: UserRole,
): Promise<ActionResponse<Boolean>> {
  const accountContext = await getActionAccountContext()
  if (!accountContext) {
    return createErrorResponse("Unauthorized")
  }

  const { userId: currentUserId } = accountContext

  try {
    // Fetch only the two specific members we need instead of loading ALL repository members
    const [currentUserMember, targetMember] = await Promise.all([
      prisma.repository_members.findUnique({
        where: { repository_id_user_id: { repository_id: repoId, user_id: currentUserId } },
        select: { role: true },
      }),
      prisma.repository_members.findFirst({
        where: { id: memberId, repository_id: repoId },
        select: { id: true, role: true, user_id: true },
      }),
    ])

    if (!currentUserMember) {
      return createErrorResponse("Repository not found")
    }

    if (!targetMember) {
      return createErrorResponse("Member not found in this repository")
    }

    // Only admins and owners can change roles
    if (currentUserMember.role !== "admin" && currentUserMember.role !== "owner") {
      return createErrorResponse("Only admins can change member roles")
    }

    // Don't allow changing owner role
    if (targetMember.role === "owner") {
      return createErrorResponse("Cannot change owner role")
    }

    if (targetMember.user_id === currentUserId) {
      return createErrorResponse("Cannot change your own role")
    }

    await prisma.repository_members.update({
      where: { id: memberId },
      data: { role: newRole },
    })

    return createSuccessResponse(true)
  } catch (error) {
    console.error("Failed to update member role:", error)
    Sentry.captureException("Failed to update member role:" + error)
    return createErrorResponse(error instanceof Error ? error.message : "Failed to update role")
  }
}

/**
 * Remove repository member
 */
export async function removeRepositoryMember(
  repoId: string,
  memberId: string,
): Promise<ActionResponse<Boolean>> {
  const accountContext = await getActionAccountContext()
  if (!accountContext) {
    return createErrorResponse("Unauthorized")
  }

  const { userId: currentUserId } = accountContext

  try {
    // Fetch only the two specific members we need instead of loading ALL repository members
    const [currentUserMember, targetMember] = await Promise.all([
      prisma.repository_members.findUnique({
        where: { repository_id_user_id: { repository_id: repoId, user_id: currentUserId } },
        select: { role: true },
      }),
      prisma.repository_members.findFirst({
        where: { id: memberId, repository_id: repoId },
        select: { id: true, role: true, user_id: true },
      }),
    ])

    if (!targetMember) {
      return createErrorResponse("Member not found in this repository")
    }

    // Cannot remove owner
    if (targetMember.role === "owner") {
      return createErrorResponse("Cannot remove repository owner")
    }

    // Check permissions
    const isAdmin = currentUserMember?.role === "admin" || currentUserMember?.role === "owner"
    const isSelf = targetMember.user_id === currentUserId

    if (!isAdmin && !isSelf) {
      return createErrorResponse("You don't have permission to remove this member")
    }

    if (isSelf) {
      return createErrorResponse("Cannot remove yourself")
    }

    await prisma.repository_members.delete({
      where: { id: memberId },
    })

    return createSuccessResponse(true)
  } catch (error) {
    console.error("Failed to remove repository member:", error)
    Sentry.captureException("Failed to remove repository member:" + error)
    return createErrorResponse(error instanceof Error ? error.message : "Failed to remove member")
  }
}
