import axios from 'axios'

export type LinkedTenantRecord = {
  id: string
  name?: string
  slug?: string
  primary_domain?: string
  timezone?: string
  default_currency?: string
  is_active?: boolean
}

export type OrganizationTenantSummary = {
  rows: LinkedTenantRecord[]
  count: number
}

export type OrganizationTenantSummaryMap = Record<string, OrganizationTenantSummary>

export const emptyOrganizationTenantSummary: OrganizationTenantSummary = {
  rows: [],
  count: 0,
}

const normalizeTenantRows = (rows: any): LinkedTenantRecord[] => {
  if (!Array.isArray(rows)) {
    return []
  }

  return rows.map((row: any) => ({
    id: row?.id,
    name: row?.name,
    slug: row?.slug,
    primary_domain: row?.primary_domain,
    timezone: row?.timezone,
    default_currency: row?.default_currency,
    is_active: row?.is_active,
  }))
}

const normalizeOrganizationId = (organizationId: any): string => {
  if (typeof organizationId === 'string') {
    return organizationId
  }

  if (Array.isArray(organizationId)) {
    return typeof organizationId[0] === 'string' ? organizationId[0] : ''
  }

  if (organizationId && typeof organizationId === 'object') {
    return typeof organizationId.id === 'string' ? organizationId.id : ''
  }

  return ''
}

const getTenantLookupErrorMessage = (error: any): string => {
  const responseData = error?.response?.data

  if (typeof responseData === 'string') {
    return responseData.toLowerCase()
  }

  if (responseData && typeof responseData === 'object') {
    const candidateMessages = [
      responseData?.message,
      responseData?.error,
      responseData?.errors?.message,
    ].filter((value) => typeof value === 'string')

    if (candidateMessages.length) {
      return candidateMessages.join(' ').toLowerCase()
    }
  }

  if (typeof error?.message === 'string') {
    return error.message.toLowerCase()
  }

  return ''
}

const isForbiddenTenantLookup = (error: any) => {
  const status = error?.response?.status
  const message = getTenantLookupErrorMessage(error)

  return (status === 400 || status === 403) && (message.includes('forbidden') || message.includes('not authorized'))
}

export const getTenantSetupHref = (organizationId?: string, organizationName?: string) => {
  if (!organizationId) {
    return '/tenants/tenants-new'
  }

  const params = new URLSearchParams({ organizationId })

  if (organizationName) {
    params.set('organizationName', organizationName)
  }

  return `/tenants/tenants-new?${params.toString()}`
}

export const getTenantViewHref = (tenantId?: string, organizationId?: string, organizationName?: string) => {
  if (!tenantId) {
    return '/tenants/tenants-list'
  }

  const params = new URLSearchParams({ id: tenantId })

  if (organizationId) {
    params.set('organizationId', organizationId)
  }

  if (organizationName) {
    params.set('organizationName', organizationName)
  }

  return `/tenants/tenants-view/?${params.toString()}`
}

export const getTenantManageHref = (
  tenantId?: string,
  organizationId?: string,
  organizationName?: string,
) => {
  if (!tenantId) {
    return '/tenants/tenants-list'
  }

  const params = new URLSearchParams({ id: tenantId })

  if (organizationId) {
    params.set('organizationId', organizationId)
  }

  if (organizationName) {
    params.set('organizationName', organizationName)
  }

  return `/tenants/tenants-edit/?${params.toString()}`
}

export const getOrganizationViewHref = (organizationId?: string, tenantId?: string, tenantName?: string) => {
  if (!organizationId) {
    return '/organizations/organizations-list'
  }

  const params = new URLSearchParams({ id: organizationId })

  if (tenantId) {
    params.set('tenantId', tenantId)
  }

  if (tenantName) {
    params.set('tenantName', tenantName)
  }

  return `/organizations/organizations-view/?${params.toString()}`
}

export const getOrganizationManageHref = (
  organizationId?: string,
  tenantId?: string,
  tenantName?: string,
) => {
  if (!organizationId) {
    return '/organizations/organizations-list'
  }

  const params = new URLSearchParams({ id: organizationId })

  if (tenantId) {
    params.set('tenantId', tenantId)
  }

  if (tenantName) {
    params.set('tenantName', tenantName)
  }

  return `/organizations/organizations-edit/?${params.toString()}`
}

export const mergeEntityOptions = (existingOptions: any[] = [], nextOptions: any[] = []) => {
  const mergedById = new Map<string, any>()

  ;[...existingOptions, ...nextOptions].forEach((item: any) => {
    if (!item?.id) {
      return
    }

    mergedById.set(item.id, item)
  })

  return Array.from(mergedById.values())
}

export const loadLinkedTenantSummary = async (organizationId: string): Promise<OrganizationTenantSummary> => {
  const normalizedOrganizationId = normalizeOrganizationId(organizationId)

  if (!normalizedOrganizationId) {
    return emptyOrganizationTenantSummary
  }

  try {
    const { data } = await axios.get('/tenants', {
      params: {
        organizations: normalizedOrganizationId,
        limit: 5,
        page: 0,
        sort: 'asc',
        field: 'name',
      },
    })

    const normalizedRows = normalizeTenantRows(data?.rows)

    return {
      rows: normalizedRows,
      count: typeof data?.count === 'number' ? data.count : normalizedRows.length,
    }
  } catch (error) {
    if (isForbiddenTenantLookup(error)) {
      console.warn(`Skipping linked tenant summary for organization ${normalizedOrganizationId} because tenant access is not available.`)
      return emptyOrganizationTenantSummary
    }

    throw error
  }
}

export const loadLinkedTenantSummaries = async (
  organizationIds: string[],
): Promise<OrganizationTenantSummaryMap> => {
  const uniqueOrganizationIds = Array.from(new Set(organizationIds.map((organizationId) => normalizeOrganizationId(organizationId)).filter(Boolean)))

  if (!uniqueOrganizationIds.length) {
    return {}
  }

  const settledResults = await Promise.allSettled(
    uniqueOrganizationIds.map(async (organizationId) => ({
      summary: await loadLinkedTenantSummary(organizationId),
    })),
  )

  return settledResults.reduce((acc: OrganizationTenantSummaryMap, result, index) => {
    const organizationId = uniqueOrganizationIds[index]

    if (result.status === 'fulfilled') {
      acc[organizationId] = result.value.summary
      return acc
    }

    console.error(`Failed to load linked tenants for organization ${organizationId}:`, result.reason)
    acc[organizationId] = emptyOrganizationTenantSummary
    return acc
  }, {})
}
