export interface SessionPayloadMergeCapable {
  mergeIntoAccessTokenPayload(payload: Record<string, unknown>): Promise<void>
}

export interface SessionPayloadUserEnvelope {
  emails: string[]
}

export interface SessionPayloadResponseEnvelope {
  status?: string
  session?: SessionPayloadMergeCapable
  user?: SessionPayloadUserEnvelope
}

function readPrimaryEmail(response: SessionPayloadResponseEnvelope) {
  return String(response.user?.emails?.[0] || '').trim().toLowerCase()
}

async function stampDefaultSessionPayload(
  response: SessionPayloadResponseEnvelope,
  {
    defaultPlan,
    defaultRole,
  }: {
    defaultPlan: string
    defaultRole: string
  },
) {
  if (response.status !== 'OK' || !response.session) {
    return
  }

  const email = readPrimaryEmail(response)
  if (!email) {
    return
  }

  await response.session.mergeIntoAccessTokenPayload({
    email,
    plan: defaultPlan,
    role: defaultRole,
  })
}

export function buildEmailPasswordApiOverrides<T extends Record<string, unknown>>(
  originalImplementation: T,
  {
    defaultPlan,
    defaultRole,
  }: {
    defaultPlan: string
    defaultRole: string
  },
) {
  const typedImplementation = originalImplementation as T & {
    signUpPOST?: (input: unknown) => Promise<SessionPayloadResponseEnvelope>
    signInPOST?: (input: unknown) => Promise<SessionPayloadResponseEnvelope>
  }

  return {
    ...originalImplementation,
    signUpPOST: async (input: unknown) => {
      const response = await typedImplementation.signUpPOST!(input)
      await stampDefaultSessionPayload(response, {
        defaultPlan,
        defaultRole,
      })
      return response
    },
    signInPOST: async (input: unknown) => {
      const response = await typedImplementation.signInPOST!(input)
      await stampDefaultSessionPayload(response, {
        defaultPlan,
        defaultRole,
      })
      return response
    },
  } as T
}
