import Axios, { InternalAxiosRequestConfig } from 'axios'
import Cookies from 'js-cookie'
import { toast } from 'react-toastify'
import { NetworkStore } from '../components/ErrorBoundary/GlobalNetworkLoadingIndicator'

// Declare the extended axios types to include our custom property
declare module 'axios' {
  export interface AxiosRequestConfig {
    workspace?: boolean
  }
}

export const isDevelopment = window.location.hostname.includes('localhost')

const tenantCode = window.location.hostname.split('.')[0]
const institutionCode = window.location.pathname.split('/')[1]

// Workspace to API endpoint prefix mapping
const workspaceApiMapping: Record<string, string> = {
  'student-workspace': '/student-api',
  'faculty-workspace': '/faculty-api',
  'department-workspace': '/department-api',
  'academic-coordinator-workspace': '/academic-coordinator-api',
  'coe-workspace': '/coe-api',
  'academic-admin-workspace': '/academic-admin-api',
  'hostel-admin-workspace': '/hostel-admin-api',
  'transport-coordinator-workspace': '/transport-coordinator-api',
  'employee-workspace': '/employee-api',
  'librarian-workspace': '/librarian-api',
  'course-coordinator-workspace': '/course-coordinator-api',
  'prospect-workspace': '/prospect-api',
  'classroom-coordinator-workspace': '/classroom-coordinator-api',
  'feedback-coordinator-workspace': '/feedback-coordinator-api',
  'team-owner-workspace': '/team-owner-api',
  'admissions-counsellor-workspace': '/admissions-counsellor-api',
  'admissions-officer-workspace': '/admissions-officer-api',
  'research-coordinator-workspace': '/research-coordinator-api',
  'payment-portal': '/payment-portal-api',
}

export const formatParams = (params) => {
  return Object.fromEntries(
    Object.entries(params ?? {})?.map((i) => [
      i[0],
      i[1] === '__empty__' ? '' : i[1],
    ]),
  )
}

let axios = Axios.create({
  baseURL: process.env.REACT_APP_API_HOST,
  withCredentials: true,
  headers: {
    'x-tenant-id': tenantCode,
    'x-institution-code': institutionCode,
  },
})

axios.interceptors.request.use(
  function (config: InternalAxiosRequestConfig) {
    const params = formatParams(config?.params)
    NetworkStore.update((s) => {
      s.loading = true
    })

    // Handle workspace routing (default: true)
    if (
      config.workspace !== false &&
      window.location.pathname.split('/')[2] &&
      window.location.pathname.split('/')[2] !== 'common-workspace' &&
      workspaceApiMapping[window.location.pathname.split('/')[2]]
    ) {
      const workspacePrefix =
        workspaceApiMapping[window.location.pathname.split('/')[2]]
      if (
        workspacePrefix &&
        typeof workspacePrefix === 'string' &&
        workspacePrefix.trim()
      ) {
        config.url = `${workspacePrefix}${config.url}`
      }
    }

    // Add session keys from cookies if available
    const sessionKey = Cookies.get('campx_session_key')
    const openPaymentsKey = Cookies.get('campx_open_payments_key')

    if (isDevelopment && sessionKey) {
      config.headers.set('campx_session_key', sessionKey)
    }

    if (openPaymentsKey) {
      config.headers.set('campx_open_payments_key', openPaymentsKey)
    }

    return {
      ...config,
      params,
    }
  },
  function (error) {
    NetworkStore.update((s) => {
      s.loading = false
    })
    return Promise.reject(error)
  },
)

axios.interceptors.response.use(
  function (response) {
    NetworkStore.update((s) => {
      s.loading = false
    })
    return response
  },
  function (err) {
    NetworkStore.update((s) => {
      s.loading = false
    })

    // Check if the error is an unauthorized error (401)
    if (err?.response && err?.response?.status === 401) {
      // Clear session keys from cookies on unauthorized error
      Cookies.remove('campx_session_key')
      Cookies.remove('campx_tenant')
      Cookies.remove('campx_institution')
    }

    return Promise.reject(err)
  },
)

export default axios

export const axiosErrorToast = (error: any, fallback?: string) => {
  const fallbackMessage = fallback ?? 'Something went wrong.'
  const errorMessage =
    typeof error?.response?.data?.message !== 'string'
      ? (error?.response?.data?.message?.join('\n') ?? fallbackMessage)
      : error?.response?.data?.message

  return toast.error(errorMessage)
}
