import { db, member, ssoProvider } from '@sim/db'
import { createLogger } from '@sim/logger'
import { and, eq } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { listSsoProvidersContract } from '@/lib/api/contracts/auth'
import { parseRequest } from '@/lib/api/server'
import { getSession } from '@/lib/auth'
import { enforceIpRateLimit } from '@/lib/core/rate-limiter'
import { REDACTED_MARKER } from '@/lib/core/security/redaction'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'

const logger = createLogger('SSOProvidersRoute')

export const GET = withRouteHandler(async (request: NextRequest) => {
  try {
    const session = await getSession()
    if (!session?.user?.id) {
      const rateLimited = await enforceIpRateLimit('sso-providers', request, {
        maxTokens: 20,
        refillRate: 20,
        refillIntervalMs: 60_000,
      })
      if (rateLimited) return rateLimited
    }
    const parsed = await parseRequest(listSsoProvidersContract, request, {})
    if (!parsed.success) return parsed.response
    const { organizationId } = parsed.data.query

    let providers
    if (session?.user?.id) {
      const userId = session.user.id

      let verifiedOrganizationId: string | null = null
      if (organizationId) {
        const [membership] = await db
          .select({ organizationId: member.organizationId, role: member.role })
          .from(member)
          .where(and(eq(member.userId, userId), eq(member.organizationId, organizationId)))
          .limit(1)
        if (!membership) {
          return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
        }
        if (membership.role !== 'owner' && membership.role !== 'admin') {
          return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
        }
        verifiedOrganizationId = membership.organizationId
      }

      const whereClause = verifiedOrganizationId
        ? eq(ssoProvider.organizationId, verifiedOrganizationId)
        : eq(ssoProvider.userId, userId)

      const results = await db
        .select({
          id: ssoProvider.id,
          providerId: ssoProvider.providerId,
          domain: ssoProvider.domain,
          issuer: ssoProvider.issuer,
          oidcConfig: ssoProvider.oidcConfig,
          samlConfig: ssoProvider.samlConfig,
          userId: ssoProvider.userId,
          organizationId: ssoProvider.organizationId,
        })
        .from(ssoProvider)
        .where(whereClause)

      providers = results.map((provider) => {
        let oidcConfig = provider.oidcConfig
        if (oidcConfig) {
          try {
            const parsed = JSON.parse(oidcConfig)
            parsed.clientSecret = REDACTED_MARKER
            oidcConfig = JSON.stringify(parsed)
          } catch {
            oidcConfig = null
          }
        }
        return {
          ...provider,
          oidcConfig,
          providerType: (provider.samlConfig ? 'saml' : 'oidc') as 'oidc' | 'saml',
        }
      })
    } else {
      const results = await db
        .select({
          domain: ssoProvider.domain,
        })
        .from(ssoProvider)

      providers = results.map((provider) => ({
        domain: provider.domain,
      }))
    }

    logger.info('Fetched SSO providers', {
      userId: session?.user?.id,
      authenticated: !!session?.user?.id,
      providerCount: providers.length,
    })

    return NextResponse.json({ providers })
  } catch (error) {
    logger.error('Failed to fetch SSO providers', { error })
    return NextResponse.json({ error: 'Failed to fetch SSO providers' }, { status: 500 })
  }
})
