import type { Category, Product } from '@/entities/product/model/types'
import { apiClient } from '@/shared/api/client'
import { apiBaseURL } from '@/shared/config'
import { ADMIN_UPLOAD_IMAGE_MAX_BYTES, formatAdminImageMaxSizeHint } from '@/shared/constants/upload-limits'

export type PublicProductsResponse = {
  items: Product[]
  total: number
  page: number
  pageSize: number
}

export async function fetchPublicProducts(params?: {
  categorySlug?: string
  q?: string
  sort?: 'price_asc' | 'price_desc' | ''
  page?: number
  pageSize?: number
  priceMinCents?: number
  priceMaxCents?: number
}): Promise<PublicProductsResponse> {
  const { data } = await apiClient.get<PublicProductsResponse>('products', {
    params: {
      categorySlug: params?.categorySlug || undefined,
      q: params?.q || undefined,
      sort: params?.sort || undefined,
      page: params?.page || undefined,
      pageSize: params?.pageSize || undefined,
      priceMin: params?.priceMinCents ?? undefined,
      priceMax: params?.priceMaxCents ?? undefined,
    },
  })
  return data
}

export async function fetchPublicProduct(id: string): Promise<Product> {
  const { data } = await apiClient.get<Product>(`products/${id}`)
  return data
}

export async function fetchCategories(): Promise<Category[]> {
  const { data } = await apiClient.get<Category[]>('categories')
  return data
}

export async function fetchAdminProducts(): Promise<Product[]> {
  const { data } = await apiClient.get<Product[]>('admin/products')
  return data
}

export async function createProduct(body: {
  title: string
  slug?: string
  shortDescription?: string | null
  description?: string | null
  quantity: number
  materials?: string[]
  priceCents: number
  imageUrl?: string | null
  imageUrls?: string[]
  published: boolean
  categoryId: string
}): Promise<Product> {
  const { data } = await apiClient.post<Product>('admin/products', body)
  return data
}

export async function updateProduct(
  id: string,
  body: Partial<{
    title: string
    slug: string
    shortDescription: string | null
    description: string | null
    quantity: number
    materials: string[]
    priceCents: number
    imageUrl: string | null
    imageUrls: string[]
    published: boolean
    categoryId: string
  }>,
): Promise<Product> {
  const { data } = await apiClient.patch<Product>(`admin/products/${id}`, body)
  return data
}

export async function deleteProduct(id: string): Promise<void> {
  await apiClient.delete(`admin/products/${id}`)
}

export async function createCategory(body: { name: string; slug?: string; sort?: number }): Promise<Category> {
  const { data } = await apiClient.post<Category>('admin/categories', body)
  return data
}

export async function fetchAdminCategories(): Promise<Category[]> {
  const { data } = await apiClient.get<{ items: Category[] }>('admin/categories')
  return data.items
}

export async function updateAdminCategory(
  id: string,
  body: Partial<{ name: string; slug: string; sort: number }>,
): Promise<Category> {
  const { data } = await apiClient.patch<Category>(`admin/categories/${id}`, body)
  return data
}

export async function deleteAdminCategory(id: string): Promise<void> {
  await apiClient.delete(`admin/categories/${id}`)
}

/** FormData: не задавать Content-Type вручную (boundary задаёт браузер). */
export async function uploadAdminProductImages(files: FileList | readonly File[]): Promise<string[]> {
  const list = Array.from(files)
  for (const f of list) {
    if (f.size > ADMIN_UPLOAD_IMAGE_MAX_BYTES) {
      throw new Error(
        `Файл «${f.name}» слишком большой (максимум ${formatAdminImageMaxSizeHint()} на одно изображение).`,
      )
    }
  }
  const fd = new FormData()
  for (const f of list) {
    fd.append('files', f, f.name)
  }
  const token = localStorage.getItem('craftshop_auth_token')
  const base = apiBaseURL.replace(/\/$/, '')
  const res = await fetch(`${base}/admin/uploads`, {
    method: 'POST',
    headers: token ? { Authorization: `Bearer ${token}` } : {},
    body: fd,
  })
  const payload = (await res.json().catch(() => ({}))) as { urls?: string[]; error?: string }
  if (!res.ok) {
    if (res.status === 413) {
      throw new Error(
        'Сервер отклонил файл как слишком большой (413). На проде часто лимит nginx: добавьте client_max_body_size для /api/ (см. docs/nginx-upload-limit.md). Проверьте также MAX_UPLOAD_BODY_BYTES в .env на сервере.',
      )
    }
    throw new Error(typeof payload.error === 'string' ? payload.error : `Ошибка загрузки (${res.status})`)
  }
  if (!Array.isArray(payload.urls)) {
    throw new Error('Некорректный ответ сервера')
  }
  return payload.urls
}
