/**
 * Meta OAuth Callback
 *
 * Verarbeitet den OAuth Callback von Meta und speichert die Tokens.
 *
 * GET /api/auth/meta/callback?code=...&state=...
 */

import { NextRequest, NextResponse } from 'next/server'
import { getPayload } from 'payload'
import config from '@payload-config'
import {
  exchangeCodeForTokens,
  getLongLivedToken,
  decodeState,
  calculateTokenExpiry,
} from '@/lib/integrations/meta/oauth'
import { MetaBaseClient } from '@/lib/integrations/meta/MetaBaseClient'
import { createSafeLogger } from '@/lib/security'
import type { MetaOAuthState } from '@/types/meta'

const logger = createSafeLogger('API:MetaCallback')

export async function GET(req: NextRequest) {
  const searchParams = req.nextUrl.searchParams
  const code = searchParams.get('code')
  const stateParam = searchParams.get('state')
  const error = searchParams.get('error')
  const errorDescription = searchParams.get('error_description')
  const errorReason = searchParams.get('error_reason')

  const baseUrl = process.env.NEXT_PUBLIC_SERVER_URL || ''

  // Fehler von Meta
  if (error) {
    logger.error('OAuth error from Meta:', { error, errorDescription, errorReason })
    return NextResponse.redirect(
      `${baseUrl}/admin/collections/social-accounts?error=${encodeURIComponent(errorDescription || error)}`
    )
  }

  // Fehlende Parameter
  if (!code || !stateParam) {
    logger.warn('Missing OAuth parameters')
    return NextResponse.redirect(
      `${baseUrl}/admin/collections/social-accounts?error=missing_params`
    )
  }

  try {
    // State decodieren
    let state: MetaOAuthState
    try {
      state = decodeState(stateParam)
    } catch {
      logger.error('Invalid state parameter')
      return NextResponse.redirect(
        `${baseUrl}/admin/collections/social-accounts?error=invalid_state`
      )
    }

    const { socialAccountId, accountType, returnUrl } = state

    if (!socialAccountId) {
      logger.error('Missing socialAccountId in state')
      return NextResponse.redirect(
        `${baseUrl}/admin/collections/social-accounts?error=invalid_state`
      )
    }

    // State-Alter prüfen (max 10 Minuten)
    const stateAge = Date.now() - state.timestamp
    if (stateAge > 10 * 60 * 1000) {
      logger.warn('State expired', { age: stateAge })
      return NextResponse.redirect(
        `${baseUrl}/admin/collections/social-accounts?error=state_expired`
      )
    }

    // Tokens von Meta abrufen (Short-lived Token)
    logger.info('Exchanging code for tokens')
    const shortLivedTokens = await exchangeCodeForTokens(code)

    if (!shortLivedTokens.access_token) {
      throw new Error('No access token received from Meta')
    }

    // Long-lived Token abrufen (60 Tage gültig)
    logger.info('Exchanging for long-lived token')
    const longLivedToken = await getLongLivedToken(shortLivedTokens.access_token)

    // Meta Client initialisieren
    const metaClient = new MetaBaseClient(longLivedToken.access_token)

    // User-Informationen abrufen
    const metaUser = await metaClient.getMe()
    logger.info('Meta user retrieved', {
      userId: metaUser.id,
      userName: metaUser.name,
    })

    // Account-spezifische Daten abrufen
    let accountData: {
      externalId: string
      accountHandle?: string
      accountUrl?: string
      followers?: number
      totalPosts?: number
      additionalData?: Record<string, unknown>
    } = {
      externalId: metaUser.id,
      accountHandle: metaUser.name,
    }

    // Je nach accountType unterschiedliche Daten abrufen
    if (accountType === 'facebook' || accountType === 'both') {
      const pages = await metaClient.getPages()
      logger.info('Facebook pages retrieved', { count: pages.length })

      // Erste Page als Haupt-Account verwenden
      if (pages.length > 0) {
        const primaryPage = pages[0]
        accountData = {
          externalId: primaryPage.id,
          accountHandle: primaryPage.name,
          accountUrl: `https://facebook.com/${primaryPage.id}`,
          additionalData: {
            pageAccessToken: primaryPage.access_token,
            category: primaryPage.category,
            allPages: pages.map((p) => ({
              id: p.id,
              name: p.name,
              category: p.category,
              hasInstagram: !!p.instagram_business_account?.id,
            })),
          },
        }
      }
    }

    if (accountType === 'instagram' || accountType === 'both') {
      const instagramAccounts = await metaClient.getAllInstagramAccounts()
      logger.info('Instagram accounts retrieved', { count: instagramAccounts.length })

      // Wenn Instagram-Account gefunden, diesen priorisieren für Instagram-Type
      if (instagramAccounts.length > 0 && accountType === 'instagram') {
        const primaryInstagram = instagramAccounts[0].instagram
        accountData = {
          externalId: primaryInstagram.id,
          accountHandle: `@${primaryInstagram.username}`,
          accountUrl: `https://instagram.com/${primaryInstagram.username}`,
          followers: primaryInstagram.followers_count,
          totalPosts: primaryInstagram.media_count,
          additionalData: {
            linkedPage: {
              id: instagramAccounts[0].page.id,
              name: instagramAccounts[0].page.name,
            },
            allInstagramAccounts: instagramAccounts.map((acc) => ({
              id: acc.instagram.id,
              username: acc.instagram.username,
              pageId: acc.page.id,
              pageName: acc.page.name,
            })),
          },
        }
      } else if (instagramAccounts.length > 0 && accountType === 'both') {
        // Bei 'both' Instagram-Daten zu den additionalData hinzufügen
        accountData.additionalData = {
          ...accountData.additionalData,
          instagramAccounts: instagramAccounts.map((acc) => ({
            id: acc.instagram.id,
            username: acc.instagram.username,
            followers: acc.instagram.followers_count,
            pageId: acc.page.id,
            pageName: acc.page.name,
          })),
        }
      }
    }

    const payload = await getPayload({ config })

    // Social Account aktualisieren
    await payload.update({
      collection: 'social-accounts',
      id: socialAccountId,
      data: {
        externalId: accountData.externalId,
        accountHandle: accountData.accountHandle,
        accountUrl: accountData.accountUrl,
        credentials: {
          accessToken: longLivedToken.access_token,
          // Meta verwendet kein separates Refresh Token - der Long-lived Token wird refreshed
          tokenExpiresAt: calculateTokenExpiry(longLivedToken.expires_in).toISOString(),
        },
        stats: {
          followers: accountData.followers || 0,
          totalPosts: accountData.totalPosts || 0,
          lastSyncedAt: new Date().toISOString(),
        },
      },
    })

    logger.info('Meta OAuth completed', {
      socialAccountId,
      accountType,
      externalId: accountData.externalId,
      accountHandle: accountData.accountHandle,
    })

    return NextResponse.redirect(`${baseUrl}${returnUrl || `/admin/collections/social-accounts/${socialAccountId}`}?success=connected`)
  } catch (err: unknown) {
    const errorMessage = err instanceof Error ? err.message : 'Unknown error'
    logger.error('OAuth callback error:', { error: errorMessage })

    return NextResponse.redirect(
      `${baseUrl}/admin/collections/social-accounts?error=${encodeURIComponent(errorMessage)}`
    )
  }
}
