import refreshTokenHelper from "../../utils/refreshTokenHelper"
import forceLogoutHelper from "../../utils/forceLogoutHelper"
import errorHandlingHelper from "../../utils/errorHandlingHelper"
import fetchHelper from '../../utils/fetchHelper'
import setAuthCookie from '../../utils/setAuthCookie'
import { trimUser, trimRole, trimOrganization, trimClient, trimWarehouse } from '../../utils/trimCookieData'
import { enforceMobileWorkerGate } from '../../utils/mobileWorkerHelper'

const selectRole = async (event: any, body: any, config: any) => {
  let data: any = {}
  const logshipSession = getCookie(event, 'logship_session')

  //@ts-ignore
  let token: string = getCookie(event, 'logship_it') //await useStorage().getItem('logship_token_'+logshipSession)

  // Optional fields are omitted entirely when unset — never send ''/undefined.
  const putBody: any = {
    clientId: body.clientId,
    roleId: body.roleId,
    organizationId: body.organizationId
  }
  if (body.warehouseId !== undefined && body.warehouseId !== null && body.warehouseId !== '') {
    putBody.warehouseId = body.warehouseId
  }
  if (body.language) {
    putBody.language = body.language
  }
  const resToken: any = await fetchHelper(event, 'auth/tokens', 'PUT', token, putBody)
  if(resToken.token) {
    setAuthCookie(event, 'logship_it', resToken.token) //await useStorage().setItem('logship_token_'+logshipSession, resToken.token)
    setAuthCookie(event, 'logship_rt', resToken.refresh_token)
    data['token'] = resToken.token
    data['refresh_token'] = resToken.refresh_token
  }
  if(resToken.userId) {
    setAuthCookie(event, 'logship_user_id', resToken.userId)
    data['userId'] = resToken.userId

    const fetchOrNull = (url: string) =>
      fetchHelper(event, url, 'GET', resToken.token, null).catch((e: any) => {
        if (e?.status === 401 || e?.status === 403) throw e
        return null
      })

    const [resUser, resClient, resRole, resOrg, resWarehouse] = await Promise.all([
      fetchOrNull('models/ad_user/' + resToken.userId),
      body.clientId       ? fetchOrNull('models/ad_client/' + body.clientId)       : Promise.resolve(null),
      body.roleId         ? fetchOrNull('models/ad_role/' + body.roleId)           : Promise.resolve(null),
      body.organizationId ? fetchOrNull('models/ad_org/' + body.organizationId)    : Promise.resolve(null),
      body.warehouseId    ? fetchOrNull('models/m_warehouse/' + body.warehouseId)  : Promise.resolve(null)
    ])

    if(resUser) {
      setAuthCookie(event, 'logship_user', trimUser(resUser))
      data['user'] = resUser
    }
    if(resClient) {
      setAuthCookie(event, 'logship_client', trimClient(resClient))
      data['client'] = resClient
    }
    if(resRole) {
      setAuthCookie(event, 'logship_role', trimRole(resRole))
      data['role'] = resRole
    }
    if(resOrg) {
      setAuthCookie(event, 'logship_organization', trimOrganization(resOrg))
      data['organization'] = resOrg
    }
    if(resWarehouse) {
      setAuthCookie(event, 'logship_warehouse', trimWarehouse(resWarehouse))
      data['warehouse'] = resWarehouse
    }

    // Honor the mobile-worker cookie only when the user record allows it.
    const wantsMobile = getCookie(event, 'logship_mw') === '1'
    enforceMobileWorkerGate(event, wantsMobile, resUser, data)
  }
  if(resToken.language) {
    setAuthCookie(event, 'logship_language', resToken.language)
    data['language'] = resToken.language
  }

  // Never write undefined/null into context cookies — a literal "undefined"
  // cookie is truthy and poisons every later login/refresh with invalid ids.
  const hasValue = (v: any) => v !== undefined && v !== null && v !== '' && v !== 'undefined' && v !== 'null'
  setAuthCookie(event, 'logship_client_id', body.clientId)
  setAuthCookie(event, 'logship_role_id', body.roleId)
  setAuthCookie(event, 'logship_organization_id', body.organizationId)
  // Reset (empty) instead of leaving a stale/junk warehouse when none was picked.
  setAuthCookie(event, 'logship_warehouse_id', hasValue(body.warehouseId) ? body.warehouseId : '')

  return data
}

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig()
  const body = await readBody(event)

  let data: any = {}

  // Fail loudly instead of PUTting undefined ids to iDempiere ("Invalid
  // roleId"/"Invalid client"/"Missing organizationId parameter" in AuthFailure.log).
  const missing = ['clientId', 'roleId', 'organizationId']
    .filter(k => body?.[k] === undefined || body?.[k] === null || body?.[k] === '')
  if (missing.length >= 1) {
    return {
      body: {
        clientId: body?.clientId,
        roleId: body?.roleId,
        organizationId: body?.organizationId,
        warehouseId: body?.warehouseId,
        language: body?.language
      },
      status: 400,
      message: 'Missing required fields: ' + missing.join(', ')
    }
  }

  try {
    data = await selectRole(event, body, config)
  } catch(err: any) {
    try {
      await refreshTokenHelper(event)
      data = await selectRole(event, body, config)
    } catch(error) {
      data = {
        body: {
          clientId: body.clientId,
          roleId: body.roleId,
          organizationId: body.organizationId,
          warehouseId: body.warehouseId,
          language: body.language
        }, 
        //@ts-ignore
        status: error.status,
        //@ts-ignore
        message: error.message
      }
    }
  }

  return data
})