import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateShortId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { googleDriveUploadContract } from '@/lib/api/contracts/tools/google'
import { parseRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { processSingleFileToUserFile } from '@/lib/uploads/utils/file-utils'
import { downloadServableFileFromStorage } from '@/lib/uploads/utils/file-utils.server'
import { docNotReadyResponse } from '@/lib/uploads/utils/servable-file-response'
import { assertToolFileAccess } from '@/app/api/files/authorization'
import {
  GOOGLE_WORKSPACE_MIME_TYPES,
  handleSheetsFormat,
  SOURCE_MIME_TYPES,
} from '@/tools/google_drive/utils'

export const dynamic = 'force-dynamic'

const logger = createLogger('GoogleDriveUploadAPI')

const GOOGLE_DRIVE_API_BASE = 'https://www.googleapis.com/upload/drive/v3/files'

/**
 * Build multipart upload body for Google Drive API
 */
function buildMultipartBody(
  metadata: Record<string, any>,
  fileBuffer: Buffer,
  mimeType: string,
  boundary: string
): string {
  const parts: string[] = []

  parts.push(`--${boundary}`)
  parts.push('Content-Type: application/json; charset=UTF-8')
  parts.push('')
  parts.push(JSON.stringify(metadata))

  parts.push(`--${boundary}`)
  parts.push(`Content-Type: ${mimeType}`)
  parts.push('Content-Transfer-Encoding: base64')
  parts.push('')
  parts.push(fileBuffer.toString('base64'))

  parts.push(`--${boundary}--`)

  return parts.join('\r\n')
}

export const POST = withRouteHandler(async (request: NextRequest) => {
  const requestId = generateRequestId()

  try {
    const authResult = await checkInternalAuth(request, { requireWorkflowId: false })

    if (!authResult.success || !authResult.userId) {
      logger.warn(`[${requestId}] Unauthorized Google Drive upload attempt: ${authResult.error}`)
      return NextResponse.json(
        {
          success: false,
          error: authResult.error || 'Authentication required',
        },
        { status: 401 }
      )
    }

    logger.info(
      `[${requestId}] Authenticated Google Drive upload request via ${authResult.authType}`,
      {
        userId: authResult.userId,
      }
    )

    const parsed = await parseRequest(googleDriveUploadContract, request, {})
    if (!parsed.success) return parsed.response
    const validatedData = parsed.data.body

    logger.info(`[${requestId}] Uploading file to Google Drive`, {
      fileName: validatedData.fileName,
      mimeType: validatedData.mimeType,
      folderId: validatedData.folderId,
      hasFile: !!validatedData.file,
    })

    if (!validatedData.file) {
      return NextResponse.json(
        {
          success: false,
          error: 'No file provided. Use the text content field for text-only uploads.',
        },
        { status: 400 }
      )
    }

    // Process file - convert to UserFile format if needed
    const fileData = validatedData.file

    let userFile
    try {
      userFile = processSingleFileToUserFile(fileData, requestId, logger)
    } catch (error) {
      return NextResponse.json(
        {
          success: false,
          error: getErrorMessage(error, 'Failed to process file'),
        },
        { status: 400 }
      )
    }

    logger.info(`[${requestId}] Downloading file from storage`, {
      fileName: userFile.name,
      key: userFile.key,
      size: userFile.size,
    })

    const denied = await assertToolFileAccess(userFile.key, authResult.userId, requestId, logger)
    if (denied) return denied

    let fileBuffer: Buffer
    let downloadedContentType = ''

    try {
      const result = await downloadServableFileFromStorage(userFile, requestId, logger)
      fileBuffer = result.buffer
      downloadedContentType = result.contentType
    } catch (error) {
      const notReady = docNotReadyResponse(error)
      if (notReady) return notReady
      logger.error(`[${requestId}] Failed to download file:`, error)
      return NextResponse.json(
        {
          success: false,
          error: `Failed to download file: ${getErrorMessage(error, 'Unknown error')}`,
        },
        { status: 500 }
      )
    }

    let uploadMimeType =
      validatedData.mimeType || downloadedContentType || userFile.type || 'application/octet-stream'
    const requestedMimeType =
      validatedData.mimeType || downloadedContentType || userFile.type || 'application/octet-stream'

    if (GOOGLE_WORKSPACE_MIME_TYPES.includes(requestedMimeType)) {
      uploadMimeType = SOURCE_MIME_TYPES[requestedMimeType] || 'text/plain'
      logger.info(`[${requestId}] Converting to Google Workspace type`, {
        requestedMimeType,
        uploadMimeType,
      })
    }

    if (requestedMimeType === 'application/vnd.google-apps.spreadsheet') {
      try {
        const textContent = fileBuffer.toString('utf-8')
        const { csv } = handleSheetsFormat(textContent)
        if (csv !== undefined) {
          fileBuffer = Buffer.from(csv, 'utf-8')
          uploadMimeType = 'text/csv'
          logger.info(`[${requestId}] Converted to CSV for Google Sheets upload`)
        }
      } catch (error) {
        logger.warn(`[${requestId}] Could not convert to CSV, uploading as-is:`, error)
      }
    }

    const metadata: {
      name: string
      mimeType: string
      parents?: string[]
    } = {
      name: validatedData.fileName,
      mimeType: requestedMimeType,
    }

    if (validatedData.folderId && validatedData.folderId.trim() !== '') {
      metadata.parents = [validatedData.folderId.trim()]
    }

    const boundary = `boundary_${Date.now()}_${generateShortId(7)}`

    const multipartBody = buildMultipartBody(metadata, fileBuffer, uploadMimeType, boundary)

    logger.info(`[${requestId}] Uploading to Google Drive via multipart upload`, {
      fileName: validatedData.fileName,
      size: fileBuffer.length,
      uploadMimeType,
      requestedMimeType,
    })

    const uploadResponse = await fetch(
      `${GOOGLE_DRIVE_API_BASE}?uploadType=multipart&supportsAllDrives=true`,
      {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${validatedData.accessToken}`,
          'Content-Type': `multipart/related; boundary=${boundary}`,
          'Content-Length': Buffer.byteLength(multipartBody, 'utf-8').toString(),
        },
        body: multipartBody,
      }
    )

    if (!uploadResponse.ok) {
      const errorText = await uploadResponse.text()
      logger.error(`[${requestId}] Google Drive API error:`, {
        status: uploadResponse.status,
        statusText: uploadResponse.statusText,
        error: errorText,
      })
      return NextResponse.json(
        {
          success: false,
          error: `Google Drive API error: ${uploadResponse.statusText}`,
        },
        { status: uploadResponse.status }
      )
    }

    const uploadData = await uploadResponse.json()
    const fileId = uploadData.id

    logger.info(`[${requestId}] File uploaded successfully`, { fileId })

    if (GOOGLE_WORKSPACE_MIME_TYPES.includes(requestedMimeType)) {
      logger.info(`[${requestId}] Updating file name to ensure it persists after conversion`)

      const updateNameResponse = await fetch(
        `https://www.googleapis.com/drive/v3/files/${fileId}?supportsAllDrives=true`,
        {
          method: 'PATCH',
          headers: {
            Authorization: `Bearer ${validatedData.accessToken}`,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            name: validatedData.fileName,
          }),
        }
      )

      if (!updateNameResponse.ok) {
        logger.warn(
          `[${requestId}] Failed to update filename after conversion, but content was uploaded`
        )
      }
    }

    const finalFileResponse = await fetch(
      `https://www.googleapis.com/drive/v3/files/${fileId}?supportsAllDrives=true&fields=id,name,mimeType,webViewLink,webContentLink,size,createdTime,modifiedTime,parents`,
      {
        headers: {
          Authorization: `Bearer ${validatedData.accessToken}`,
        },
      }
    )

    const finalFile = await finalFileResponse.json()

    logger.info(`[${requestId}] Upload complete`, {
      fileId: finalFile.id,
      fileName: finalFile.name,
      webViewLink: finalFile.webViewLink,
    })

    return NextResponse.json({
      success: true,
      output: {
        file: {
          id: finalFile.id,
          name: finalFile.name,
          mimeType: finalFile.mimeType,
          webViewLink: finalFile.webViewLink,
          webContentLink: finalFile.webContentLink,
          size: finalFile.size,
          createdTime: finalFile.createdTime,
          modifiedTime: finalFile.modifiedTime,
          parents: finalFile.parents,
        },
      },
    })
  } catch (error) {
    logger.error(`[${requestId}] Error uploading file to Google Drive:`, error)

    return NextResponse.json(
      {
        success: false,
        error: getErrorMessage(error, 'Internal server error'),
      },
      { status: 500 }
    )
  }
})
