// One typed client method per count endpoint (docs/11-BACKEND-PHASE1.md §5.6).
// In-memory Stock Core (lib/api/mock-data.ts) — no backend API calls.
import { PagedResponse } from "@/types/common"
import {
  CountStatus,
  CreateCountRequest,
  EnterCountsRequest,
  EnterCountsResponse,
  PostCountResponse,
  StockCount,
  StockCountSummary,
} from "@/types/stock"
import {
  allocateAdjLineId,
  allocateAdjustmentId,
  allocateCountId,
  allocateCountLineId,
  computeOnHand,
  consumeFifo,
  lastKnownCost,
  mockDelay,
  mockStockAdjustments,
  mockStockCounts,
  postLedgerEntry,
  receiveLayer,
} from "@/lib/api/mock-data"

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

function toSummary(c: (typeof mockStockCounts)[number]): StockCountSummary {
  return {
    countId: c.countId,
    docNo: c.docNo,
    warehouseId: c.warehouseId,
    countType: c.countType,
    status: c.status,
    createdAt: c.createdAt,
  }
}

export const stockCountsApi = {
  list(params: ListCountsParams = {}): Promise<PagedResponse<StockCountSummary>> {
    const filtered = mockStockCounts
      .filter((c) => !params.warehouseId || c.warehouseId === params.warehouseId)
      .map(toSummary)
      .sort((a, b) => b.countId - a.countId)

    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(countId: number): Promise<StockCount> {
    const c = mockStockCounts.find((x) => x.countId === countId)
    if (!c) return Promise.reject(new Error(`Mock count ${countId} not found`))
    return mockDelay(c)
  },

  create(request: CreateCountRequest): Promise<StockCount> {
    const countId = allocateCountId()
    const count = {
      countId,
      docNo: `CNT-2026-${String(countId).padStart(5, "0")}`,
      warehouseId: request.warehouseId,
      countType: request.countType,
      status: "Draft" as CountStatus,
      createdBy: 17,
      createdAt: new Date().toISOString(),
      lines: request.itemIds.map((itemId) => ({
        countLineId: allocateCountLineId(),
        itemId,
        binId: null,
        systemQty: computeOnHand(itemId, request.warehouseId).onHand,
        countedQty: null,
        variance: null,
      })),
    }
    mockStockCounts.push(count)
    return mockDelay(count)
  },

  enterCounts(countId: number, request: EnterCountsRequest): Promise<EnterCountsResponse> {
    const c = mockStockCounts.find((x) => x.countId === countId)
    if (!c) return Promise.reject(new Error(`Mock count ${countId} not found`))

    for (const input of request.lines) {
      const line = c.lines.find((l) => l.countLineId === input.countLineId)
      if (!line) continue
      line.countedQty = input.countedQty
      line.variance = Math.round((input.countedQty - line.systemQty) * 100) / 100
    }
    return mockDelay({ lines: c.lines })
  },

  post(countId: number): Promise<PostCountResponse> {
    const c = mockStockCounts.find((x) => x.countId === countId)
    if (!c) return Promise.reject(new Error(`Mock count ${countId} not found`))
    if (c.status === "Posted") return Promise.reject(new Error(`${c.docNo} has already been posted.`))

    const adjustmentId = allocateAdjustmentId()
    const ledgerRefs: number[] = []
    const adjLines: { adjLineId: number; itemId: number; binId: number | null; batchId: number | null; qtyDelta: number }[] = []

    for (const line of c.lines) {
      if (!line.variance) continue
      adjLines.push({ adjLineId: allocateAdjLineId(), itemId: line.itemId, binId: line.binId, batchId: null, qtyDelta: line.variance })

      if (line.variance > 0) {
        const unitCost = lastKnownCost(line.itemId, c.warehouseId)
        const { ledger } = receiveLayer({
          itemId: line.itemId,
          warehouseId: c.warehouseId,
          qty: line.variance,
          unitCost,
          userId: 17,
          sourceDocType: "Count",
          sourceDocId: c.countId,
        })
        ledgerRefs.push(ledger.ledgerId)
      } else {
        const chunks = consumeFifo(line.itemId, c.warehouseId, Math.abs(line.variance))
        for (const chunk of chunks) {
          const ledger = postLedgerEntry({
            itemId: line.itemId,
            warehouseId: c.warehouseId,
            userId: 17,
            direction: "Out",
            qtyBase: chunk.qtyConsumed,
            unitCost: chunk.unitCost,
            sourceDocType: "Count",
            sourceDocId: c.countId,
          })
          ledgerRefs.push(ledger.ledgerId)
        }
      }
    }

    // Count Variance reason code (docs/8.3 seed list) — posted as its own adjustment record.
    mockStockAdjustments.push({
      adjustmentId,
      docNo: `ADJ-2026-${String(adjustmentId).padStart(5, "0")}`,
      warehouseId: c.warehouseId,
      reasonCodeId: 3,
      status: "Posted",
      createdBy: 17,
      createdAt: new Date().toISOString(),
      lines: adjLines,
      ledgerRefs,
    })

    c.status = "Posted"
    return mockDelay({ countId: c.countId, status: c.status, adjustmentId, ledgerRefs })
  },
}
