"use server"

import { ActionResponse, createErrorResponse, createSuccessResponse } from "@/lib/action-response"
import { GitHubUserSearchResult, Member, UserRole } from "@/lib/types"
import {
  deleteOrganizationMemberApiKeys,
  organizationMemberRepository,
  prisma,
} from "@codeflash-ai/common"
import { Prisma } from "@prisma/client"
import { withTiming } from "@/lib/server-action-timing"
import { trackMemberInvited } from "@/lib/analytics/tracking"
import { getActionAccountContext } from "@/lib/server/get-account-context"

/**
 * Get organization members
 */
export const getOrganizationMembers = withTiming(
  "getOrganizationMembers",
  async (organizationId: string): Promise<ActionResponse<Member[]>> => {
    const accountContext = await getActionAccountContext()
    if (!accountContext) {
      return createErrorResponse("Unauthorized")
    }

    const { userId: currentUserId } = accountContext

    try {
      // Check access via indexed composite key in parallel with member fetch
      const [org, accessCheck] = await Promise.all([
        prisma.organizations.findUnique({
          where: { id: organizationId },
          select: {
            id: true,
            organization_members: {
              include: {
                user: { select: { user_id: true, github_username: true, name: true, email: true } },
              },
              orderBy: {
                added_at: "asc",
              },
            },
          },
        }),
        prisma.organization_members.findUnique({
          where: {
            organization_id_user_id: { organization_id: organizationId, user_id: currentUserId },
          },
          select: { id: true },
        }),
      ])

      if (!org) {
        return createErrorResponse("Organization not found")
      }

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

      const members: Member[] = org.organization_members.map(
        (member: {
          id: string
          user_id: string
          role: string
          added_at: Date
          user: {
            user_id: string
            github_username: string
            name: string | null
            email: string | null
          }
        }) => ({
          id: member.id,
          user_id: member.user_id,
          username: member.user.github_username,
          name: member.user.name,
          email: member.user.email,
          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 organization members:", error)
      return createErrorResponse(error instanceof Error ? error.message : "Failed to get members")
    }
  },
)

/**
 * Add a member to organization
 */
export async function addOrganizationMember(
  invitedUser: GitHubUserSearchResult,
  role: UserRole,
  organizationId: string,
): Promise<ActionResponse<Member>> {
  const accountContext = await getActionAccountContext()
  if (!accountContext) {
    return createErrorResponse("Unauthorized")
  }

  const { userId: currentUserId } = accountContext

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

    // Verify org exists and check permissions + duplicate in parallel using indexed lookups
    // instead of loading the entire organization_members array
    const [orgExists, currentUserMember, existingMember] = await Promise.all([
      prisma.organizations.findUnique({
        where: { id: organizationId },
        select: { id: true },
      }),
      prisma.organization_members.findUnique({
        where: {
          organization_id_user_id: { organization_id: organizationId, user_id: currentUserId },
        },
        select: { role: true },
      }),
      prisma.organization_members.findUnique({
        where: {
          organization_id_user_id: { organization_id: organizationId, user_id: invitedUserId },
        },
        select: { id: true },
      }),
    ])

    if (!orgExists) {
      return createErrorResponse("Organization not found")
    }

    // Check if user has permission to add members
    const isAdmin = currentUserMember?.role === "admin" || currentUserMember?.role === "owner"

    if (!isAdmin) {
      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 organization")
    }

    // Ensure user exists in our database (upsert handles concurrent invites safely)
    const user = await prisma.users.upsert({
      where: { user_id: invitedUserId },
      update: {},
      create: {
        user_id: invitedUserId,
        github_username: invitedUser.username,
        onboarding_completed: false,
      },
    })

    let newMember
    try {
      // Add user to organization members
      newMember = await prisma.organization_members.create({
        data: {
          organization_id: organizationId,
          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 organization")
      }
      throw error
    }

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

    return createSuccessResponse({
      id: String(newMember.id),
      user_id: String(newMember.user_id),
      username: invitedUser.username,
      name: user.name ?? null,
      email: user.email ?? null,
      role: String(newMember.role),
      added_at:
        newMember.added_at instanceof Date
          ? newMember.added_at
          : new Date(String(newMember.added_at)),
      avatarUrl: invitedUser.avatarUrl,
    })
  } catch (error) {
    console.error("Failed to add organization member:", error)
    return createErrorResponse(error instanceof Error ? error.message : "Failed to add member")
  }
}

/**
 * Update organization member role
 */
export async function updateOrganizationMemberRole(
  organizationId: string,
  memberId: string,
  newRole: "admin" | "member" | "owner",
): 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 members
    const [currentUserMember, targetMember] = await Promise.all([
      prisma.organization_members.findUnique({
        where: {
          organization_id_user_id: { organization_id: organizationId, user_id: currentUserId },
        },
        select: { role: true },
      }),
      prisma.organization_members.findFirst({
        where: { id: memberId, organization_id: organizationId },
        select: { id: true, role: true, user_id: true },
      }),
    ])

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

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

    // 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 as the only admin")
    }

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

    return createSuccessResponse(true)
  } catch (error) {
    console.error("Failed to update member role:", error)
    return createErrorResponse("Failed to update role")
  }
}

/**
 * Remove organization member
 */
export async function removeOrganizationMember(
  organizationId: 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 members
    const [currentUserMember, targetMember] = await Promise.all([
      prisma.organization_members.findUnique({
        where: {
          organization_id_user_id: { organization_id: organizationId, user_id: currentUserId },
        },
        select: { role: true },
      }),
      prisma.organization_members.findFirst({
        where: { id: memberId, organization_id: organizationId },
        select: { id: true, role: true, user_id: true },
      }),
    ])

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

    // Cannot remove owner
    if (targetMember.role === "owner") {
      return createErrorResponse("Cannot remove organization 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 as the only admin")
    }

    // Delete all organization API keys created by this user before removing them
    await deleteOrganizationMemberApiKeys(targetMember.user_id, organizationId)

    await organizationMemberRepository.delete(memberId)

    return createSuccessResponse(true)
  } catch (error) {
    console.error("Failed to remove organization member:", error)
    return createErrorResponse("Failed to remove member")
  }
}

/**
 * Get current user's role in organization
 */
export async function getCurrentUserRole(
  organizationId: string,
): Promise<ActionResponse<{ role: UserRole }>> {
  const accountContext = await getActionAccountContext()
  if (!accountContext) {
    return createErrorResponse("Unauthorized")
  }

  const { userId } = accountContext

  try {
    const member = await prisma.organization_members.findUnique({
      where: {
        organization_id_user_id: { organization_id: organizationId, user_id: userId },
      },
      select: { role: true },
    })

    if (!member) {
      return createErrorResponse("Member not found")
    }

    return createSuccessResponse({ role: member.role as UserRole })
  } catch (error) {
    console.error("Failed to get user role:", error)
    return createErrorResponse(error instanceof Error ? error.message : "Failed to get user role")
  }
}
