// One typed client method per Item endpoint (docs/11-BACKEND-PHASE1.md §2.1, FR-MD-01/05/08).
// `list` also backs the GRN/PO/Requisition/RFQ item pickers built in earlier sessions.
// In-memory sample data (lib/api/mock-data.ts) — no backend API calls.
import { ApiResult, EntityStatus, PagedResponse } from "@/types/common"
import {
  CreateItemRequest,
  Item,
  ItemListItem,
  TrackingMode,
  UpdateItemReorderRequest,
  UpdateItemRequest,
  UpdateUomConversionsRequest,
  UpdateUomConversionsResponse,
} from "@/types/master-data"
import {
  allocateItemId,
  bumpItemVersion,
  getItemVersion,
  initItemVersion,
  mockDelay,
  mockItems,
} from "@/lib/api/mock-data"

export interface ListItemsParams {
  page?: number
  pageSize?: number
  q?: string
  status?: EntityStatus
  categoryId?: number
  trackingMode?: TrackingMode
}

function toListItem(item: Item): ItemListItem {
  return {
    itemId: item.itemId,
    sku: item.sku,
    name: item.name,
    categoryId: item.categoryId,
    brandId: item.brandId ?? null,
    baseUomId: item.baseUomId,
    defaultVendorId: item.defaultVendorId,
    itemType: item.itemType,
    trackingMode: item.trackingMode,
    taxClass: item.taxClass,
    status: item.status,
  }
}

function skuTaken(sku: string, excludeItemId?: number) {
  return mockItems.some((i) => i.itemId !== excludeItemId && i.sku.toLowerCase() === sku.toLowerCase())
}

export const itemsApi = {
  list(params: ListItemsParams = {}): Promise<PagedResponse<ItemListItem>> {
    const term = params.q?.trim().toLowerCase()
    const filtered = mockItems
      .filter((i) => !params.status || i.status === params.status)
      .filter((i) => !params.categoryId || i.categoryId === params.categoryId)
      .filter((i) => !params.trackingMode || i.trackingMode === params.trackingMode)
      .filter((i) => !term || `${i.sku} ${i.name}`.toLowerCase().includes(term))
      .sort((a, b) => a.sku.localeCompare(b.sku))
      .map(toListItem)

    const page = params.page ?? 1
    const pageSize = params.pageSize ?? 20
    const start = (page - 1) * pageSize
    const items = filtered.slice(start, start + pageSize)

    return mockDelay({
      items,
      pagination: { page, pageSize, totalItems: filtered.length, totalPages: Math.ceil(filtered.length / pageSize) || 0 },
    })
  },

  get(itemId: number): Promise<ApiResult<Item>> {
    const item = mockItems.find((i) => i.itemId === itemId)
    if (!item) return Promise.reject(new Error(`Mock item ${itemId} not found`))
    return mockDelay({ data: item, etag: String(getItemVersion(itemId)) })
  },

  create(request: CreateItemRequest): Promise<ApiResult<Item>> {
    const sku = request.sku.trim()
    if (!sku) return Promise.reject(new Error("SKU is required."))
    if (skuTaken(sku)) {
      return Promise.reject(Object.assign(new Error(`SKU "${sku}" already exists.`), { code: "SKU_DUPLICATE" }))
    }
    const item: Item = {
      itemId: allocateItemId(),
      sku,
      name: request.name.trim(),
      description: request.description?.trim() || null,
      categoryId: request.categoryId,
      brandId: request.brandId ?? null,
      baseUomId: request.baseUomId,
      defaultVendorId: request.defaultVendorId ?? null,
      itemType: request.itemType,
      trackingMode: request.trackingMode,
      taxClass: request.taxClass?.trim() || null,
      status: "Active",
      reorder: [],
      conversions: [],
      initialQty: request.initialQty ?? null,
      createdAt: new Date().toISOString(),
      updatedAt: null,
    }
    mockItems.push(item)
    initItemVersion(item.itemId)
    return mockDelay({ data: item, etag: "1" })
  },

  update(itemId: number, request: UpdateItemRequest, ifMatch: string): Promise<ApiResult<Item>> {
    const item = mockItems.find((i) => i.itemId === itemId)
    if (!item) return Promise.reject(new Error(`Mock item ${itemId} not found`))
    if (String(getItemVersion(itemId)) !== ifMatch) {
      return Promise.reject(Object.assign(new Error("The item was modified by another request."), { code: "CONCURRENCY_CONFLICT" }))
    }
    const sku = request.sku.trim()
    if (!sku) return Promise.reject(new Error("SKU is required."))
    if (skuTaken(sku, itemId)) {
      return Promise.reject(Object.assign(new Error(`SKU "${sku}" already exists.`), { code: "SKU_DUPLICATE" }))
    }

    item.sku = sku
    item.name = request.name.trim()
    item.description = request.description?.trim() || null
    item.categoryId = request.categoryId
    item.brandId = request.brandId ?? null
    item.baseUomId = request.baseUomId
    item.defaultVendorId = request.defaultVendorId ?? null
    item.itemType = request.itemType
    item.trackingMode = request.trackingMode
    item.taxClass = request.taxClass?.trim() || null
    item.updatedAt = new Date().toISOString()

    const next = bumpItemVersion(itemId)
    return mockDelay({ data: item, etag: String(next) })
  },

  updateStatus(itemId: number, status: EntityStatus): Promise<void> {
    const item = mockItems.find((i) => i.itemId === itemId)
    if (!item) return Promise.reject(new Error(`Mock item ${itemId} not found`))
    item.status = status
    item.updatedAt = new Date().toISOString()
    bumpItemVersion(itemId)
    return mockDelay(undefined)
  },

  updateReorder(itemId: number, request: UpdateItemReorderRequest): Promise<{ settings: UpdateItemReorderRequest["settings"] }> {
    const item = mockItems.find((i) => i.itemId === itemId)
    if (!item) return Promise.reject(new Error(`Mock item ${itemId} not found`))
    item.reorder = request.settings
    item.updatedAt = new Date().toISOString()
    bumpItemVersion(itemId)
    return mockDelay({ settings: item.reorder })
  },

  updateUomConversions(itemId: number, request: UpdateUomConversionsRequest): Promise<UpdateUomConversionsResponse> {
    const item = mockItems.find((i) => i.itemId === itemId)
    if (!item) return Promise.reject(new Error(`Mock item ${itemId} not found`))
    item.conversions = request.conversions.map((c, i) => ({ conversionId: 1000 + itemId * 10 + i, fromUom: c.fromUom, toUom: c.toUom, factor: c.factor }))
    item.updatedAt = new Date().toISOString()
    bumpItemVersion(itemId)
    return mockDelay({ itemId: item.itemId, baseUomId: item.baseUomId, conversions: item.conversions })
  },
}
