import { Auth } from '@/features/User/oidcAuth'
import { assertWebSocketAlive } from '@/websocket/connection/lifecycle/assertWebSocketAlive'
import ky from 'ky'
import { getRetryDelay } from './getRetryDelay'

const MUTATING_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])

const RETRY_CONFIG = {
  maxRetries: 10,
  initialDelay: 1000,
  maxDelay: 120000
}

export const api = ky.extend({
  prefixUrl: window.CALENDAR_BASE_URL,
  retry: {
    limit: RETRY_CONFIG.maxRetries,
    backoffLimit: RETRY_CONFIG.maxDelay,
    delay: attemptCount =>
      getRetryDelay(attemptCount - 1, {
        initialDelay: RETRY_CONFIG.initialDelay,
        maxDelay: RETRY_CONFIG.maxDelay
      })
  },
  hooks: {
    beforeRequest: [
      async request => {
        const saved = sessionStorage.getItem('tokenSet')
          ? JSON.parse(sessionStorage.getItem('tokenSet') ?? '{}')
          : null
        const access_token = saved?.access_token
        if (access_token) {
          request.headers.set('Authorization', `Bearer ${access_token}`)
        }

        if (MUTATING_METHODS.has(request.method)) {
          await assertWebSocketAlive()
        }
        return request
      }
    ],

    beforeRetry: [
      ({ request, error, retryCount }) => {
        console.warn(
          `[API Retry] Attempt ${retryCount}/${RETRY_CONFIG.maxRetries}`,
          {
            url: request.url,
            error: error?.message
          }
        )
      }
    ],

    afterResponse: [
      async (request, options, response) => {
        if (response.status === 401) {
          // Check if we're already on login flow to prevent redirect loop
          const currentPath = window.location.pathname
          if (currentPath === '/callback') {
            return response
          }

          // Check if we have a token in the request
          const hasAuthHeader = request.headers.has('Authorization')
          if (!hasAuthHeader) {
            return response
          }

          // Only redirect to SSO if we're sure token is invalid (not just missing)
          const loginurl = await Auth()

          sessionStorage.setItem(
            'redirectState',
            JSON.stringify({
              code_verifier: loginurl.code_verifier,
              state: loginurl.state
            })
          )
          redirectTo(loginurl.redirectTo)
        }
        return response
      }
    ]
  }
})

export function redirectTo(url: URL) {
  window.location.assign(url)
}

export function getLocation() {
  return window.location.href
}

export function isValidUrl(string?: string) {
  let url

  try {
    url = new URL(string ?? '')
  } catch {
    return false
  }
  return url
}

export async function importFile(file: File) {
  const response = await api.post(
    `api/files?mimetype=${file.type}&name=${file.name}&size=${file.size}`,
    { body: await file.text() }
  )
  return await response.json()
}
