import axios, { AxiosError, type InternalAxiosRequestConfig } from 'axios'
import { getAccessToken, refreshTokens, clearTokens } from './auth'
import { toast } from './toast'

export const api = axios.create({
  baseURL: '',
  headers: { 'Content-Type': 'application/json' },
})

api.interceptors.request.use((config: InternalAxiosRequestConfig) => {
  const token = getAccessToken()
  if (token) {
    config.headers.set('Authorization', `Bearer ${token}`)
  }
  // SuperAdmin «открыть как…»: добавляем X-Org-Override на каждый запрос если
  // в localStorage активна выбранная орга (и эндпоинт не сам super-admin).
  const asOrg = getOrgOverride()
  if (asOrg && !(config.url ?? '').startsWith('/api/super-admin/')) {
    config.headers.set('X-Org-Override', asOrg.id)
    const edit = getEditMode()
    if (edit && edit.expiresAt > Date.now()) {
      config.headers.set('X-Org-Override-Reason', edit.reason)
    }
  }
  return config
})

const ORG_OVERRIDE_KEY = 'superAdminAsOrg'
export interface OrgOverride { id: string; name: string }
export function getOrgOverride(): OrgOverride | null {
  try {
    const raw = localStorage.getItem(ORG_OVERRIDE_KEY)
    return raw ? JSON.parse(raw) as OrgOverride : null
  } catch { return null }
}
export function setOrgOverride(value: OrgOverride | null, opts?: { redirectTo?: string }) {
  if (value) localStorage.setItem(ORG_OVERRIDE_KEY, JSON.stringify(value))
  else { localStorage.removeItem(ORG_OVERRIDE_KEY); localStorage.removeItem(EDIT_MODE_KEY) }
  // Hard navigation чтобы (а) снести TanStack Query кэш, (б) гарантированно
  // выйти из текущего layout'а в нужный (override → tenant /dashboard,
  // выход → /super-admin/organizations). Без redirectTo — просто reload
  // на ту же страницу (старое поведение, для совместимости).
  if (typeof window !== 'undefined') {
    if (opts?.redirectTo) window.location.assign(opts.redirectTo)
    else window.location.reload()
  }
}

const EDIT_MODE_KEY = 'superAdminEditMode'
export interface EditMode { reason: string; expiresAt: number }
export function getEditMode(): EditMode | null {
  try {
    const raw = localStorage.getItem(EDIT_MODE_KEY)
    if (!raw) return null
    const v = JSON.parse(raw) as EditMode
    if (v.expiresAt < Date.now()) { localStorage.removeItem(EDIT_MODE_KEY); return null }
    return v
  } catch { return null }
}
/** Включает edit-mode на 30 минут (по таймеру localStorage). После
 * истечения axios перестаёт слать reason, мутации снова блокируются. */
export function enableEditMode(reason: string) {
  const v: EditMode = { reason: reason.trim(), expiresAt: Date.now() + 30 * 60 * 1000 }
  localStorage.setItem(EDIT_MODE_KEY, JSON.stringify(v))
  if (typeof window !== 'undefined') window.location.reload()
}
export function disableEditMode() {
  localStorage.removeItem(EDIT_MODE_KEY)
  if (typeof window !== 'undefined') window.location.reload()
}

let refreshing: Promise<string | null> | null = null

api.interceptors.response.use(
  (res) => res,
  async (error: AxiosError) => {
    const original = error.config as InternalAxiosRequestConfig & { __retried?: boolean; __silent?: boolean }
    if (error.response?.status === 401 && !original.__retried) {
      original.__retried = true
      refreshing ??= refreshTokens().finally(() => { refreshing = null })
      const newToken = await refreshing
      if (newToken) {
        original.headers.set('Authorization', `Bearer ${newToken}`)
        return api(original)
      }
      clearTokens()
      // Redirect to login so user isn't stuck on a protected page with stale tokens.
      if (typeof window !== 'undefined' && !window.location.pathname.startsWith('/login')) {
        window.location.href = '/login'
      }
      // На редиректе ничего не показываем — иначе мигнёт «не авторизован».
      return Promise.reject(error)
    }
    // Toast: 4xx/5xx (кроме 401 и __silent=true) → читаем message из ответа.
    // Старое поведение было «молчаливый rej», ошибки не доходили до юзера
    // если страница не отображала mutation.error явно.
    const status = error.response?.status
    if (status && status >= 400 && status !== 401 && !original.__silent) {
      toast.error(humanizeAxios(error), { title: errorTitle(status) })
    }
    return Promise.reject(error)
  },
)

function errorTitle(status: number): string | undefined {
  if (status === 403) return 'Нет доступа'
  if (status === 404) return 'Не найдено'
  if (status === 409) return 'Конфликт'
  if (status === 422) return 'Проверьте поля'
  if (status === 429) return 'Слишком много запросов'
  if (status >= 500) return 'Ошибка сервера'
  return undefined
}

/** Извлекает человеко-читаемый текст из ответа API. Бэкенд использует
 * ProblemDetails (RFC 7807) с `title`/`detail`/`errors`; иногда отдаёт
 * простой `message`/`error`/`error_description`. Падать в крайнем случае
 * — на статус-текст («Internal Server Error»). Экспортируется, чтобы
 * страницы с form-level error display'ем (ProductEditPage и др.) могли
 * показывать ту же подсказку, что и toast. */
export function humanizeError(err: AxiosError | Error): string {
  if (!('isAxiosError' in err) && !((err as AxiosError).response)) {
    // обычный Error (не axios) — возвращаем message
    return err.message
  }
  return humanizeAxios(err as AxiosError)
}

function humanizeAxios(err: AxiosError): string {
  const data = err.response?.data as Record<string, unknown> | undefined
  if (data && typeof data === 'object') {
    // ASP.NET validation errors: { errors: { Field: ['msg', ...] } }
    const errs = data.errors as Record<string, string[]> | undefined
    if (errs && typeof errs === 'object') {
      const first = Object.values(errs).flat()[0]
      if (typeof first === 'string' && first.trim()) return first
    }
    const detail = data.detail ?? data.message ?? data.error_description ?? data.error
    if (typeof detail === 'string' && detail.trim()) return detail
    const title = data.title
    if (typeof title === 'string' && title.trim()) return title
  }
  if (err.message && !err.message.toLowerCase().includes('request failed')) return err.message
  return `Ошибка ${err.response?.status ?? ''} ${err.response?.statusText ?? ''}`.trim()
}
