// "Wastage" is not a distinct document type in docs/10-BACKEND-PHASE1.md or the SRS —
// stock write-offs (damage, theft/loss, expiry) are modelled as Stock Adjustments with a
// mandatory reason code (FR-STK-07), and the seeded reason codes (docs/10 §B.8.3) already
// include Damage / Theft-Loss / Expiry Write-off. This module is a frontend-only lens over
// stockAdjustmentsApi: filtered to loss-type reasons and flattened to per-line records for
// a focused "record wastage" flow and report. No new backend concept.
import { reasonCodesApi } from "@/lib/api/reason-codes"
import { stockAdjustmentsApi } from "@/lib/api/stock-adjustments"
import { stockApi } from "@/lib/api/stock"
import { StockAdjustment } from "@/types/stock"

/**
 * Reason codes treated as "wastage" (loss-type) causes. These match the seeded codes in
 * Infra/Persistence/DataSeeder.cs — DMG/THEFT/EXP. (`VAR` count-variance and `SYS`
 * corrections are adjustments too, but they are not losses, so they stay out.)
 */
const WASTAGE_CODES = new Set(["DMG", "THEFT", "EXP"])

/** Sync predicate for screens that already hold the reason-code list. */
export function isWastageReasonCode(code: string): boolean {
  return WASTAGE_CODES.has(code)
}

export async function wastageReasonCodeIds(): Promise<number[]> {
  const res = await reasonCodesApi.list("Adjustment", { pageSize: 200 })
  return res.items.filter((r) => isWastageReasonCode(r.code)).map((r) => r.reasonCodeId)
}

export interface WastageRecord {
  adjustmentId: number
  adjLineId: number
  docNo: string
  createdAt: string
  warehouseId: number
  itemId: number
  binId: number | null
  reasonCodeId: number
  /** Positive quantity wasted (the underlying adjustment line is a negative qtyDelta). */
  qty: number
  /** FIFO cost of the wasted quantity, summed from the ledger entries this adjustment posted. */
  value: number
}

export interface ListWastageParams {
  warehouseId?: number
  reasonCodeId?: number
  page?: number
  pageSize?: number
}

export interface RecordWastageInput {
  warehouseId: number
  itemId: number
  binId?: number | null
  qty: number
  reasonCodeId: number
}

export const wastageApi = {
  /**
   * Flattens loss-type adjustments to per-item records.
   *
   * Costs come from the ledger rather than being recomputed here: FIFO consumption is the
   * server's job, and the browser cannot see the layers (docs/20 §3.3). One ledger call per
   * adjustment is the price of the ledger's polymorphic source reference — acceptable
   * because the adjustment page is already bounded.
   */
  async list(params: ListWastageParams = {}): Promise<WastageRecord[]> {
    const wastageIds = new Set(await wastageReasonCodeIds())
    if (wastageIds.size === 0) return []

    // The API filters by a single reasonCodeId, so a specific pick can be pushed down;
    // otherwise fetch the page and keep the loss-type rows.
    const res = await stockAdjustmentsApi.list({
      warehouseId: params.warehouseId,
      reasonCodeId: params.reasonCodeId,
      page: params.page,
      pageSize: params.pageSize ?? 50,
    })
    const summaries = res.items.filter((a) => wastageIds.has(a.reasonCodeId))

    const detailed = await Promise.all(
      summaries.map(async (summary) => {
        const [adjustment, ledger] = await Promise.all([
          stockAdjustmentsApi.get(summary.adjustmentId),
          stockApi.ledger({ sourceDocType: "ADJ", sourceDocId: summary.adjustmentId, pageSize: 200 }),
        ])

        return adjustment.lines
          .filter((line) => line.qtyDelta < 0) // wastage is always a decrease
          .map<WastageRecord>((line) => {
            const value = ledger.items
              .filter((l) => l.itemId === line.itemId && l.direction === "Out")
              .reduce((sum, l) => sum + l.value, 0)
            return {
              adjustmentId: adjustment.adjustmentId,
              adjLineId: line.adjLineId,
              docNo: adjustment.docNo,
              createdAt: adjustment.createdAt,
              warehouseId: adjustment.warehouseId,
              itemId: line.itemId,
              binId: line.binId,
              reasonCodeId: adjustment.reasonCodeId,
              qty: Math.abs(line.qtyDelta),
              value: Math.round(value * 100) / 100,
            }
          })
      }),
    )

    return detailed.flat().sort((a, b) => b.adjustmentId - a.adjustmentId)
  },

  /** Records wastage as a single-line, negative-qtyDelta stock adjustment (FR-STK-07). */
  record(input: RecordWastageInput): Promise<StockAdjustment> {
    return stockAdjustmentsApi.create({
      warehouseId: input.warehouseId,
      reasonCodeId: input.reasonCodeId,
      lines: [{ itemId: input.itemId, binId: input.binId ?? null, qtyDelta: -Math.abs(input.qty) }],
    })
  },
}
