import { string } from 'alga-js'
import refreshTokenHelper from "../../../utils/refreshTokenHelper"
import errorHandlingHelper from "../../../utils/errorHandlingHelper"
import fetchHelper from "../../../utils/fetchHelper"
import getTokenHelper from "../../../utils/getTokenHelper"

export default defineEventHandler(async (event) => {
  const query = getQuery(event)
  const code = query.code as string | undefined
  const state = query.state as string | undefined // UID of the order source

  // If user declined or error occurred on eBay side
  if (!code || !state) {
    const errorMsg = encodeURIComponent(query.error_description as string || 'eBay authorization was declined or failed')
    return sendRedirect(event, `/settings/order-sources?oauth_error=${errorMsg}`, 302)
  }

  // Look up the order source by UID
  let orderSource: any = null
  let token: string | null = null
  try {
    token = await getTokenHelper(event)
    const res: any = await fetchHelper(
      event,
      `models/c_ordersource?$filter=${string.urlEncode(`C_OrderSource_UU eq '${state}'`)}`,
      'GET',
      token,
      null
    )
    orderSource = res?.records?.[0]
  } catch (err: any) {
    try {
      token = await refreshTokenHelper(event)
      const res: any = await fetchHelper(
        event,
        `models/c_ordersource?$filter=${string.urlEncode(`C_OrderSource_UU eq '${state}'`)}`,
        'GET',
        token,
        null
      )
      orderSource = res?.records?.[0]
    } catch (error: any) {
      const errorMsg = encodeURIComponent('Failed to fetch order source during OAuth callback')
      return sendRedirect(event, `/settings/order-sources?oauth_error=${errorMsg}`, 302)
    }
  }

  if (!orderSource) {
    const errorMsg = encodeURIComponent('Order source not found')
    return sendRedirect(event, `/settings/order-sources?oauth_error=${errorMsg}`, 302)
  }

  const orderSourceId = orderSource.id
  const clientId = orderSource.SHOPWARE_KEY || orderSource.marketplace_key
  const clientSecret = orderSource.SHOPWARE_SECRET || orderSource.marketplace_secret
  const ruName = orderSource.ebay_ru_name
  const environment = orderSource.ebay_environment || 'production'

  if (!clientId || !clientSecret || !ruName) {
    const errorMsg = encodeURIComponent('Order source missing eBay credentials')
    return sendRedirect(event, `/settings/order-sources/${orderSourceId}/edit?oauth_error=${errorMsg}`, 302)
  }

  // Exchange authorization code for tokens
  const tokenUrl = environment === 'sandbox'
    ? 'https://api.sandbox.ebay.com/identity/v1/oauth2/token'
    : 'https://api.ebay.com/identity/v1/oauth2/token'

  const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64')

  let tokenResponse: any = null
  try {
    tokenResponse = await $fetch(tokenUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': `Basic ${credentials}`,
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        code: code,
        redirect_uri: ruName,
      }).toString(),
    })
  } catch (err: any) {
    console.error('eBay token exchange error:', err?.data || err?.message || err)
    const errorMsg = encodeURIComponent(err?.data?.error_description || 'Failed to exchange authorization code for tokens')
    return sendRedirect(event, `/settings/order-sources/${orderSourceId}/edit?oauth_error=${errorMsg}`, 302)
  }

  if (!tokenResponse?.access_token) {
    const errorMsg = encodeURIComponent('eBay did not return an access token')
    return sendRedirect(event, `/settings/order-sources/${orderSourceId}/edit?oauth_error=${errorMsg}`, 302)
  }

  // Build token JSON blob to store
  const tokenBlob = JSON.stringify({
    access_token: tokenResponse.access_token,
    refresh_token: tokenResponse.refresh_token,
    token_type: tokenResponse.token_type,
    expires_in: tokenResponse.expires_in,
    refresh_token_expires_in: tokenResponse.refresh_token_expires_in,
    obtained_at: new Date().toISOString(),
  })

  // Save tokens to order source in iDempiere
  try {
    await fetchHelper(event, `models/c_ordersource/${orderSourceId}`, 'PUT', token, {
      marketplace_token: tokenBlob,
      tableName: 'c_ordersource',
    })
  } catch (err: any) {
    // Try with refreshed token
    try {
      token = await refreshTokenHelper(event)
      await fetchHelper(event, `models/c_ordersource/${orderSourceId}`, 'PUT', token, {
        marketplace_token: tokenBlob,
        tableName: 'c_ordersource',
      })
    } catch (error: any) {
      console.error('Failed to save eBay tokens:', error?.data || error?.message || error)
      const errorMsg = encodeURIComponent('Tokens obtained but failed to save to order source')
      return sendRedirect(event, `/settings/order-sources/${orderSourceId}/edit?oauth_error=${errorMsg}`, 302)
    }
  }

  return sendRedirect(event, `/settings/order-sources/${orderSourceId}/edit?oauth_success=1`, 302)
})
