import { useAuthStore } from '../stores/auth'

let loginRedirectStarted = false

function redirectToLogin(): void {
  if (loginRedirectStarted || window.location.pathname === '/login') return
  loginRedirectStarted = true

  const currentTarget = `${window.location.pathname}${window.location.search}${window.location.hash}`
  const loginUrl = new URL('/login', window.location.origin)
  if (currentTarget !== '/') loginUrl.searchParams.set('redirect', currentTarget)
  window.location.assign(`${loginUrl.pathname}${loginUrl.search}`)
}

export async function apiFetch(input: RequestInfo | URL, init: RequestInit = {}) {
  const auth = useAuthStore()
  if (!auth.initialized) await auth.initialize()

  const send = () => {
    // openapi-fetch supplies a fully built Request object. Preserve its
    // Content-Type, idempotency and correlation headers before applying
    // explicit overrides and the current auth token.
    const headers = new Headers(
      typeof Request !== 'undefined' && input instanceof Request
        ? input.headers
        : undefined,
    )
    new Headers(init.headers).forEach((value, key) => headers.set(key, value))
    if (auth.accessToken) headers.set('Authorization', `Bearer ${auth.accessToken}`)
    // Set Content-Type for JSON body requests — needed because fetch() defaults
    // to text/plain for string bodies, which ASP.NET rejects for [FromBody] binding.
    if (typeof init.body === 'string' && !headers.has('Content-Type')) {
      headers.set('Content-Type', 'application/json')
    }
    return fetch(input, { ...init, headers, credentials: 'include' })
  }

  let response = await send()
  if (response.status !== 401) return response

  const refreshed = await auth.refresh()
  if (!refreshed) {
    redirectToLogin()
    return response
  }

  response = await send()
  return response
}
