// One typed client method per adjustment endpoint (docs/11-BACKEND-PHASE1.md §5.5).
// In-memory Stock Core (lib/api/mock-data.ts) — no backend API calls.
import { PagedResponse } from "@/types/common"
import { AdjustmentStatus, CreateAdjustmentRequest, StockAdjustment, StockAdjustmentSummary } from "@/types/stock"
import {
  allocateAdjLineId,
  allocateAdjustmentId,
  consumeFifo,
  lastKnownCost,
  mockDelay,
  mockStockAdjustments,
  postLedgerEntry,
  receiveLayer,
} from "@/lib/api/mock-data"

export interface ListAdjustmentsParams {
  page?: number
  pageSize?: number
  warehouseId?: number
}

function toSummary(a: (typeof mockStockAdjustments)[number]): StockAdjustmentSummary {
  return {
    adjustmentId: a.adjustmentId,
    docNo: a.docNo,
    warehouseId: a.warehouseId,
    reasonCodeId: a.reasonCodeId,
    status: a.status,
    createdAt: a.createdAt,
  }
}

export const stockAdjustmentsApi = {
  list(params: ListAdjustmentsParams = {}): Promise<PagedResponse<StockAdjustmentSummary>> {
    const filtered = mockStockAdjustments
      .filter((a) => !params.warehouseId || a.warehouseId === params.warehouseId)
      .map(toSummary)
      .sort((a, b) => b.adjustmentId - a.adjustmentId)

    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(adjustmentId: number): Promise<StockAdjustment> {
    const a = mockStockAdjustments.find((x) => x.adjustmentId === adjustmentId)
    if (!a) return Promise.reject(new Error(`Mock adjustment ${adjustmentId} not found`))
    return mockDelay(a)
  },

  create(request: CreateAdjustmentRequest): Promise<StockAdjustment> {
    if (!request.reasonCodeId) {
      return Promise.reject(Object.assign(new Error("A reason code is required for adjustments."), { code: "REASON_CODE_REQUIRED" }))
    }

    const adjustmentId = allocateAdjustmentId()
    const ledgerRefs: number[] = []
    const lines: StockAdjustment["lines"] = []

    try {
      for (const line of request.lines) {
        const adjLineId = allocateAdjLineId()
        lines.push({ adjLineId, itemId: line.itemId, binId: line.binId ?? null, batchId: line.batchId ?? null, qtyDelta: line.qtyDelta })

        if (line.qtyDelta > 0) {
          // FR-STK-07: increase creates a layer at the last known cost.
          const unitCost = lastKnownCost(line.itemId, request.warehouseId)
          const { ledger } = receiveLayer({
            itemId: line.itemId,
            warehouseId: request.warehouseId,
            binId: line.binId,
            batchId: line.batchId,
            qty: line.qtyDelta,
            unitCost,
            userId: 17,
            sourceDocType: "Adjustment",
            sourceDocId: adjustmentId,
          })
          ledgerRefs.push(ledger.ledgerId)
        } else if (line.qtyDelta < 0) {
          // Decrease consumes FIFO layers (409 STOCK_NEGATIVE_BLOCKED if insufficient).
          const chunks = consumeFifo(line.itemId, request.warehouseId, Math.abs(line.qtyDelta))
          for (const chunk of chunks) {
            const ledger = postLedgerEntry({
              itemId: line.itemId,
              warehouseId: request.warehouseId,
              binId: line.binId,
              batchId: line.batchId,
              userId: 17,
              direction: "Out",
              qtyBase: chunk.qtyConsumed,
              unitCost: chunk.unitCost,
              sourceDocType: "Adjustment",
              sourceDocId: adjustmentId,
            })
            ledgerRefs.push(ledger.ledgerId)
          }
        }
      }
    } catch (err) {
      return Promise.reject(err)
    }

    const adjustment = {
      adjustmentId,
      docNo: `ADJ-2026-${String(adjustmentId).padStart(5, "0")}`,
      warehouseId: request.warehouseId,
      reasonCodeId: request.reasonCodeId,
      status: "Posted" as AdjustmentStatus,
      createdBy: 17,
      createdAt: new Date().toISOString(),
      lines,
      ledgerRefs,
    }
    mockStockAdjustments.push(adjustment)
    return mockDelay(adjustment)
  },
}
