import { db } from '@sim/db'
import { credential, credentialMember, user } from '@sim/db/schema'
import { createLogger } from '@sim/logger'
import { generateId } from '@sim/utils/id'
import { and, eq } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { upsertWorkspaceCredentialMemberContract } from '@/lib/api/contracts/credentials'
import { parseRequest } from '@/lib/api/server'
import { getSession } from '@/lib/auth'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'

const logger = createLogger('CredentialMembersAPI')

interface RouteContext {
  params: Promise<{ id: string }>
}

async function requireWorkspaceAdminMembership(credentialId: string, userId: string) {
  const [cred] = await db
    .select({ id: credential.id, workspaceId: credential.workspaceId })
    .from(credential)
    .where(eq(credential.id, credentialId))
    .limit(1)

  if (!cred) return null

  const perm = await getUserEntityPermissions(userId, 'workspace', cred.workspaceId)
  if (perm === null) return null

  const [membership] = await db
    .select({ role: credentialMember.role, status: credentialMember.status })
    .from(credentialMember)
    .where(
      and(eq(credentialMember.credentialId, credentialId), eq(credentialMember.userId, userId))
    )
    .limit(1)

  if (!membership || membership.status !== 'active' || membership.role !== 'admin') {
    return null
  }
  return membership
}

export const GET = withRouteHandler(async (_request: NextRequest, context: RouteContext) => {
  try {
    const session = await getSession()
    if (!session?.user?.id) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const { id: credentialId } = await context.params

    const [cred] = await db
      .select({ id: credential.id, workspaceId: credential.workspaceId })
      .from(credential)
      .where(eq(credential.id, credentialId))
      .limit(1)

    if (!cred) {
      return NextResponse.json({ error: 'Not found' }, { status: 404 })
    }

    const callerPerm = await getUserEntityPermissions(
      session.user.id,
      'workspace',
      cred.workspaceId
    )
    if (callerPerm === null) {
      return NextResponse.json({ error: 'Not found' }, { status: 404 })
    }

    const members = await db
      .select({
        id: credentialMember.id,
        userId: credentialMember.userId,
        role: credentialMember.role,
        status: credentialMember.status,
        joinedAt: credentialMember.joinedAt,
        userName: user.name,
        userEmail: user.email,
      })
      .from(credentialMember)
      .innerJoin(user, eq(credentialMember.userId, user.id))
      .where(eq(credentialMember.credentialId, credentialId))

    return NextResponse.json({ members })
  } catch (error) {
    logger.error('Failed to fetch credential members', { error })
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
  }
})

export const POST = withRouteHandler(async (request: NextRequest, context: RouteContext) => {
  try {
    const session = await getSession()
    if (!session?.user?.id) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const { id: credentialId } = await context.params

    const admin = await requireWorkspaceAdminMembership(credentialId, session.user.id)
    if (!admin) {
      return NextResponse.json({ error: 'Admin access required' }, { status: 403 })
    }

    const parsed = await parseRequest(upsertWorkspaceCredentialMemberContract, request, context)
    if (!parsed.success) return parsed.response

    const { userId, role } = parsed.data.body
    const now = new Date()

    const [existing] = await db
      .select({ id: credentialMember.id, status: credentialMember.status })
      .from(credentialMember)
      .where(
        and(eq(credentialMember.credentialId, credentialId), eq(credentialMember.userId, userId))
      )
      .limit(1)

    if (existing) {
      const ok = await db.transaction(async (tx) => {
        const [current] = await tx
          .select({ role: credentialMember.role, status: credentialMember.status })
          .from(credentialMember)
          .where(eq(credentialMember.id, existing.id))
          .limit(1)
          .for('update')
        if (current?.role === 'admin' && current?.status === 'active' && role !== 'admin') {
          const activeAdmins = await tx
            .select({ id: credentialMember.id })
            .from(credentialMember)
            .where(
              and(
                eq(credentialMember.credentialId, credentialId),
                eq(credentialMember.role, 'admin'),
                eq(credentialMember.status, 'active')
              )
            )
            .for('update')
          if (activeAdmins.length <= 1) return false
        }
        await tx
          .update(credentialMember)
          .set({ role, status: 'active', updatedAt: now })
          .where(eq(credentialMember.id, existing.id))
        return true
      })
      if (!ok) {
        return NextResponse.json({ error: 'Cannot demote the last admin' }, { status: 400 })
      }
      return NextResponse.json({ success: true })
    }

    await db.insert(credentialMember).values({
      id: generateId(),
      credentialId,
      userId,
      role,
      status: 'active',
      joinedAt: now,
      invitedBy: session.user.id,
      createdAt: now,
      updatedAt: now,
    })

    return NextResponse.json({ success: true }, { status: 201 })
  } catch (error) {
    logger.error('Failed to add credential member', { error })
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
  }
})

export const DELETE = withRouteHandler(async (request: NextRequest, context: RouteContext) => {
  try {
    const session = await getSession()
    if (!session?.user?.id) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const { id: credentialId } = await context.params
    const targetUserId = new URL(request.url).searchParams.get('userId')
    if (!targetUserId) {
      return NextResponse.json({ error: 'userId query parameter required' }, { status: 400 })
    }

    const admin = await requireWorkspaceAdminMembership(credentialId, session.user.id)
    if (!admin) {
      return NextResponse.json({ error: 'Admin access required' }, { status: 403 })
    }

    const [target] = await db
      .select({
        id: credentialMember.id,
        role: credentialMember.role,
      })
      .from(credentialMember)
      .where(
        and(
          eq(credentialMember.credentialId, credentialId),
          eq(credentialMember.userId, targetUserId),
          eq(credentialMember.status, 'active')
        )
      )
      .limit(1)

    if (!target) {
      return NextResponse.json({ error: 'Member not found' }, { status: 404 })
    }

    const revoked = await db.transaction(async (tx) => {
      if (target.role === 'admin') {
        const activeAdmins = await tx
          .select({ id: credentialMember.id })
          .from(credentialMember)
          .where(
            and(
              eq(credentialMember.credentialId, credentialId),
              eq(credentialMember.role, 'admin'),
              eq(credentialMember.status, 'active')
            )
          )
          .for('update')

        if (activeAdmins.length <= 1) {
          return false
        }
      }

      await tx
        .update(credentialMember)
        .set({ status: 'revoked', updatedAt: new Date() })
        .where(eq(credentialMember.id, target.id))

      return true
    })

    if (!revoked) {
      return NextResponse.json({ error: 'Cannot remove the last admin' }, { status: 400 })
    }

    return NextResponse.json({ success: true })
  } catch (error) {
    logger.error('Failed to remove credential member', { error })
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
  }
})
