// Единственное место, где приложение читает код ответа и разбирает тело отказа.
// Экран получает готовый текст, а не `Response`: второй разборщик кодов на
// клиенте разошёлся бы с первым.

const appRoot = '/app'

/** Ответ сервиса на вопрос «кто вошёл». */
export interface Me {
  id: string
  name: string
}

/** Единая форма тела отказа на адресах приложения. */
interface ErrorBody {
  error_code?: string
  message?: string
}

/**
 * Исход запроса. Отсутствие сессии — свой исход, а не разновидность неудачи:
 * экран уводит ко входу только на нём. Всякий прочий отказ ко входу не ведёт,
 * иначе отказ сервиса или ограничителя частоты замкнул бы круг «приложение →
 * вход → приложение».
 */
export type ApiResult<T> =
  | { status: 'ok'; value: T }
  | { status: 'unauthorized' }
  | { status: 'failed'; message: string }

const noConnectionMessage = 'Связи нет'
const unknownFailureMessage = 'Сервис не отвечает как надо'

async function failureMessage(response: Response): Promise<string> {
  try {
    const body = (await response.json()) as ErrorBody
    if (body.message) {
      return body.message
    }
  } catch {
    // Тело не разобралось — своего текста под код ответа не сочиняем.
  }
  return unknownFailureMessage
}

async function request<T>(path: string): Promise<ApiResult<T>> {
  let response: Response
  try {
    response = await fetch(appRoot + path, {
      headers: { Accept: 'application/json' },
    })
  } catch {
    // Сорванный запрос — состояние, а не ошибка: показываем строкой.
    return { status: 'failed', message: noConnectionMessage }
  }

  if (response.status === 401) {
    return { status: 'unauthorized' }
  }

  if (!response.ok) {
    return { status: 'failed', message: await failureMessage(response) }
  }

  try {
    return { status: 'ok', value: (await response.json()) as T }
  } catch {
    return { status: 'failed', message: unknownFailureMessage }
  }
}

/** Спрашивает сервис, кто вошёл. Куку сессии браузер шлёт сам. */
export function fetchMe(): Promise<ApiResult<Me>> {
  return request<Me>('/me')
}

/** Адрес, которым сервис уводит человека ко входу. */
export const loginPath = '/auth/login'
