import { useTranslation } from 'react-i18next'
import axios from 'axios'
import { Alert } from './alert'
import { Button } from './button'
import { ArrowClockwiseIcon } from '@phosphor-icons/react'

/**
 * Friendly error renderer для TanStack Query errors. Замена паттерна
 * {@code <Alert variant="error">{String(error)}</Alert>} который раздавал
 * raw {@code "AxiosError: Request failed with status code 503"} в UI.
 *
 * <p>Маппинг status → human message:
 * <ul>
 *   <li>503/502/504 — сервер временно недоступен (rolling restart, GW timeout)</li>
 *   <li>500 — внутренняя ошибка сервера</li>
 *   <li>404 — не найдено</li>
 *   <li>403 — нет доступа</li>
 *   <li>401 — handled global'ным interceptor'ом, но fallback'нем</li>
 *   <li>network err — нет соединения</li>
 *   <li>default — generic failure с raw message только в debug режиме</li>
 * </ul>
 *
 * <p>Backend code/message парсятся если возвращены: вместо `AxiosError: ...`
 * показывается {@code body.message} (что backend сам положил). Это работает
 * только для structured 4xx responses; 5xx обычно plain html error page.
 *
 * <p>Retry кнопка — opt-in через {@code onRetry} prop. Caller передаёт
 * {@code () => query.refetch()}.
 */

export type QueryErrorStateProps = {
  /** TanStack Query error (или любая Error/unknown) */
  error: unknown
  /** Optional retry callback — обычно `() => query.refetch()`. */
  onRetry?: () => void
  /** Optional title override (по умолчанию по status code'у). */
  title?: React.ReactNode
  /** className для Alert wrapper (e.g. mt-4). */
  className?: string
}

type ErrorClassification = {
  titleKey: string
  titleFallback: string
  bodyKey: string
  bodyFallback: string
  /** Можно retry'нуть. False для permanent errors (404/403). */
  retryable: boolean
  /** Backend-provided code (если был structured response). */
  backendCode?: string
  /** Backend-provided human message (если был). */
  backendMessage?: string
}

function classify(error: unknown): ErrorClassification {
  if (axios.isAxiosError(error)) {
    const status = error.response?.status
    const body = error.response?.data as
      | { code?: string; message?: string; error?: string }
      | undefined
    const backendCode = body?.code
    const backendMessage = body?.message ?? body?.error

    // Network error (no response, e.g. DNS, offline, CORS preflight failed).
    if (!error.response) {
      return {
        titleKey: 'queryError.network.title',
        titleFallback: 'Нет соединения с сервером',
        bodyKey: 'queryError.network.body',
        bodyFallback: 'Проверьте сеть. Когда соединение восстановится — повторите.',
        retryable: true,
      }
    }

    if (status === 503 || status === 502 || status === 504) {
      return {
        titleKey: 'queryError.unavailable.title',
        titleFallback: 'Сервер временно недоступен',
        bodyKey: 'queryError.unavailable.body',
        bodyFallback:
          'Возможно идёт обновление или плановое обслуживание. Подождите несколько секунд и повторите.',
        retryable: true,
      }
    }
    if (status === 500) {
      return {
        titleKey: 'queryError.server.title',
        titleFallback: 'Внутренняя ошибка сервера',
        bodyKey: 'queryError.server.body',
        bodyFallback:
          'Что-то пошло не так на стороне сервера. Если ошибка повторяется — сообщите администратору.',
        retryable: true,
        backendCode,
        backendMessage,
      }
    }
    if (status === 404) {
      return {
        titleKey: 'queryError.notFound.title',
        titleFallback: 'Не найдено',
        bodyKey: 'queryError.notFound.body',
        bodyFallback: 'Запрашиваемые данные не существуют или были удалены.',
        retryable: false,
        backendCode,
        backendMessage,
      }
    }
    if (status === 403) {
      return {
        titleKey: 'queryError.forbidden.title',
        titleFallback: 'Нет доступа',
        bodyKey: 'queryError.forbidden.body',
        bodyFallback: 'У вас нет прав на просмотр этих данных.',
        retryable: false,
        backendCode,
        backendMessage,
      }
    }
    if (status === 401) {
      return {
        titleKey: 'queryError.unauthorized.title',
        titleFallback: 'Требуется вход',
        bodyKey: 'queryError.unauthorized.body',
        bodyFallback: 'Сессия истекла. Войдите снова чтобы продолжить.',
        retryable: false,
      }
    }
    if (status && status >= 400 && status < 500) {
      return {
        titleKey: 'queryError.client.title',
        titleFallback: 'Запрос некорректен',
        bodyKey: 'queryError.client.body',
        bodyFallback: backendMessage ?? 'Сервер отклонил запрос.',
        retryable: false,
        backendCode,
        backendMessage,
      }
    }
  }

  // Non-axios error: Error instance or unknown
  const msg =
    error instanceof Error
      ? error.message
      : typeof error === 'string'
        ? error
        : 'unknown error'
  return {
    titleKey: 'queryError.generic.title',
    titleFallback: 'Не удалось загрузить данные',
    bodyKey: 'queryError.generic.body',
    bodyFallback: msg,
    retryable: true,
  }
}

export function QueryErrorState({
  error,
  onRetry,
  title,
  className,
}: QueryErrorStateProps) {
  const { t } = useTranslation()
  const c = classify(error)

  // Backend message приоритетней generic — если backend сказал что-то
  // понятное в body.message, покажем это. Иначе fallback.
  const body = c.backendMessage
    ? c.backendMessage
    : t(c.bodyKey, { defaultValue: c.bodyFallback })
  // Alert.title типизирован как HTML title (string) из-за HTMLAttributes
  // intersection с custom React.ReactNode. Stringify чтобы TS не ругался —
  // в practice title всегда plain string label.
  const titleStr =
    typeof title === 'string'
      ? title
      : String(title ?? t(c.titleKey, { defaultValue: c.titleFallback }))

  return (
    <Alert
      variant="error"
      title={titleStr}
      className={className}
      action={
        c.retryable && onRetry ? (
          <Button
            variant="ghost"
            size="sm"
            onClick={onRetry}
            leftIcon={<ArrowClockwiseIcon weight="regular" size={14} />}
          >
            {t('queryError.retry', { defaultValue: 'Повторить' })}
          </Button>
        ) : undefined
      }
    >
      <div className="space-y-1">
        <div className="text-body">{body}</div>
        {c.backendCode && (
          <div className="text-cap text-mute font-mono uppercase tracking-wider">
            code: {c.backendCode}
          </div>
        )}
      </div>
    </Alert>
  )
}
