import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { googleSheetsSelectorContract } from '@/lib/api/contracts/selectors/google'
import { parseRequest } from '@/lib/api/server'
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { getScopesForService } from '@/lib/oauth/utils'
import { refreshAccessTokenIfNeeded, ServiceAccountTokenError } from '@/app/api/auth/oauth/utils'

export const dynamic = 'force-dynamic'

const logger = createLogger('GoogleSheetsAPI')

interface SheetProperties {
  sheetId: number
  title: string
  index: number
}

interface Sheet {
  properties: SheetProperties
}

interface SpreadsheetResponse {
  sheets: Sheet[]
}

/**
 * Get sheets (tabs) from a Google Spreadsheet
 */
export const GET = withRouteHandler(async (request: NextRequest) => {
  const requestId = generateRequestId()
  logger.info(`[${requestId}] Google Sheets sheets request received`)

  const auth = await checkSessionOrInternalAuth(request)
  if (!auth.success || !auth.userId) {
    return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
  }

  try {
    const parsed = await parseRequest(
      googleSheetsSelectorContract,
      request,
      {},
      {
        validationErrorResponse: (error) => {
          const missingCredential = error.issues.some((issue) => issue.path[0] === 'credentialId')
          if (missingCredential) {
            logger.warn(`[${requestId}] Missing credentialId parameter`)
            return NextResponse.json({ error: 'Credential ID is required' }, { status: 400 })
          }

          logger.warn(`[${requestId}] Missing spreadsheetId parameter`)
          return NextResponse.json({ error: 'Spreadsheet ID is required' }, { status: 400 })
        },
      }
    )
    if (!parsed.success) return parsed.response

    const { credentialId, spreadsheetId } = parsed.data.query
    const workflowId = parsed.data.query.workflowId || undefined
    const impersonateEmail = parsed.data.query.impersonateEmail || undefined

    const authz = await authorizeCredentialUse(request, { credentialId, workflowId })
    if (!authz.ok || !authz.credentialOwnerUserId) {
      return NextResponse.json({ error: authz.error || 'Unauthorized' }, { status: 403 })
    }

    const accessToken = await refreshAccessTokenIfNeeded(
      credentialId,
      authz.credentialOwnerUserId,
      requestId,
      getScopesForService('google-sheets'),
      impersonateEmail
    )

    if (!accessToken) {
      return NextResponse.json({ error: 'Failed to obtain valid access token' }, { status: 401 })
    }

    logger.info(
      `[${requestId}] Fetching sheets from Google Sheets API for spreadsheet ${spreadsheetId}`
    )

    // Fetch spreadsheet metadata to get sheet names
    const sheetsResponse = await fetch(
      `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}?fields=sheets.properties`,
      {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${accessToken}`,
          'Content-Type': 'application/json',
        },
      }
    )

    if (!sheetsResponse.ok) {
      const errorData = await sheetsResponse
        .text()
        .then((text) => JSON.parse(text))
        .catch(() => ({ error: { message: 'Unknown error' } }))
      logger.error(`[${requestId}] Google Sheets API error`, {
        status: sheetsResponse.status,
        error: errorData.error?.message || 'Failed to fetch sheets',
      })
      return NextResponse.json(
        { error: errorData.error?.message || 'Failed to fetch sheets' },
        { status: sheetsResponse.status }
      )
    }

    const data: SpreadsheetResponse = await sheetsResponse.json()
    const sheets = data.sheets || []

    // Sort sheets by index
    sheets.sort((a, b) => a.properties.index - b.properties.index)

    logger.info(`[${requestId}] Successfully fetched ${sheets.length} sheets`)

    return NextResponse.json({
      sheets: sheets.map((sheet) => ({
        id: sheet.properties.title, // Use title as ID since that's what the API uses
        name: sheet.properties.title,
        sheetId: sheet.properties.sheetId,
        index: sheet.properties.index,
      })),
    })
  } catch (error) {
    if (error instanceof ServiceAccountTokenError) {
      logger.warn(`[${requestId}] Service account token error`, { message: error.message })
      return NextResponse.json({ error: error.message }, { status: 400 })
    }
    logger.error(`[${requestId}] Error fetching Google Sheets sheets`, error)
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
  }
})
