import { string } from 'alga-js'

// Per-credential token cache: each custom DHL account (different OrderSource) gets
// its own cached token. TTL of 50 minutes leaves a safety margin under DHL's
// typical 1-hour token lifetime.
const TOKEN_TTL_MS = 50 * 60 * 1000
const COOKIE_MAX_AGE_S = 50 * 60
const tokenCache = new Map<string, { token: string; expiry: number }>()

const cacheKey = (credential: any): string =>
  `${credential?.dhlkey ?? ''}:${credential?.dhluser ?? ''}:${credential?.dhlurl ?? ''}`

const getToken = async (credential: any) => {
  const config = {
    api: credential
  }

  return await $fetch(config.api.dhlurl+'/account/auth/ropc/v1/token', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: `grant_type=password&username=${string.urlEncode(config.api.dhluser)}&password=${string.urlEncode(config.api.dhlpass)}&client_id=${string.urlEncode(config.api.dhlkey)}&client_secret=${string.urlEncode(config.api.dhlsecret)}`
  })
}

const persistToken = (event: any, credential: any, token: string) => {
  tokenCache.set(cacheKey(credential), { token, expiry: Date.now() + TOKEN_TTL_MS })
  setCookie(event, 'logship_bdhtl2', token, { maxAge: COOKIE_MAX_AGE_S })
}

const resolveToken = async (event: any, credential: any): Promise<string> => {
  const key = cacheKey(credential)
  const cached = tokenCache.get(key)
  if (cached && cached.expiry > Date.now()) {
    return cached.token
  }
  const cookieToken = getCookie(event, 'logship_bdhtl2') ?? ''
  if (cookieToken !== '') {
    return cookieToken
  }
  const res = await getToken(credential)
  if (res?.access_token) {
    persistToken(event, credential, res.access_token)
    return res.access_token
  }
  return ''
}

export default async function dhlCustomHelper(event: any, credential: any, url: string, method: string = 'GET', body: any) {
  const config = {
    api: credential
  }
  let token = await resolveToken(event, credential)

  let options: any = {}
  if(body) {
    options = {
      ...options,
      body: body
    }
  }

  try {
    return await $fetch(config.api.dhlurl+'/'+url, {
      method: method,
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Authorization: 'Bearer ' + token
      },
      ...options
    })
  } catch(err: any) {
    // If it's a validation error (400), don't retry with new token - it won't help
    if(err?.statusCode === 400 || err?.status === 400) {
      console.error('[DHL Custom API Error] Validation error (400):', JSON.stringify(err?.data, null, 2))
      throw err
    }

    // Invalidate cache: token may have been revoked even though our TTL says it's good.
    tokenCache.delete(cacheKey(credential))

    const res2 = await getToken(credential)
    if(res2?.access_token) {
      token = res2.access_token
      persistToken(event, credential, token)
    }

    return await $fetch(config.api.dhlurl+'/'+url, {
      method: method,
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Authorization: 'Bearer ' + token
      },
      ...options
    })
  }

}