// One typed client method per vendor (supplier) endpoint (docs/11-BACKEND-PHASE1.md
// §2.4, FR-MD-06). ETag/If-Match on update, PATCH status for deactivate (masters
// are deactivated, not hard-deleted, FR-MD-08). In-memory sample data
// (lib/api/mock-data.ts) — no backend API calls.
import { ApiResult, EntityStatus, PagedResponse } from "@/types/common"
import { Vendor } from "@/types/master-data"
import {
  allocateVendorId,
  bumpVendorVersion,
  getVendorVersion,
  initVendorVersion,
  mockDelay,
  mockVendors,
} from "@/lib/api/mock-data"

export interface ListVendorsParams {
  page?: number
  pageSize?: number
  q?: string
  status?: EntityStatus
}

export interface CreateVendorRequest {
  code: string
  name: string
  terms?: string | null
  taxReg?: string | null
  currency: string
}

export type UpdateVendorRequest = CreateVendorRequest

function codeTaken(code: string, excludeVendorId?: number) {
  return mockVendors.some((v) => v.vendorId !== excludeVendorId && v.code.toLowerCase() === code.toLowerCase())
}

export const vendorsApi = {
  list(params: ListVendorsParams = {}): Promise<PagedResponse<Vendor>> {
    const term = params.q?.trim().toLowerCase()
    const filtered = mockVendors
      .filter((v) => !params.status || v.status === params.status)
      .filter((v) => !term || `${v.code} ${v.name}`.toLowerCase().includes(term))

    const page = params.page ?? 1
    const pageSize = params.pageSize ?? 20
    const start = (page - 1) * pageSize
    const items = filtered.slice(start, start + pageSize)
    const totalItems = filtered.length
    const totalPages = pageSize <= 0 ? 0 : Math.ceil(totalItems / pageSize)

    return mockDelay({
      items,
      pagination: { page, pageSize, totalItems, totalPages },
    })
  },

  get(vendorId: number): Promise<ApiResult<Vendor>> {
    const v = mockVendors.find((x) => x.vendorId === vendorId)
    if (!v) return Promise.reject(new Error(`Mock vendor ${vendorId} not found`))
    return mockDelay({ data: v, etag: String(getVendorVersion(vendorId)) })
  },

  create(request: CreateVendorRequest): Promise<ApiResult<Vendor>> {
    const code = request.code.trim()
    if (!code) return Promise.reject(new Error("Vendor code is required."))
    if (codeTaken(code)) {
      return Promise.reject(Object.assign(new Error(`Vendor code "${code}" already exists.`), { code: "SKU_DUPLICATE" }))
    }
    const vendor: Vendor = {
      vendorId: allocateVendorId(),
      code,
      name: request.name.trim(),
      terms: request.terms?.trim() || null,
      taxReg: request.taxReg?.trim() || null,
      currency: request.currency.trim().toUpperCase(),
      status: "Active",
      createdAt: new Date().toISOString(),
      updatedAt: null,
    }
    mockVendors.push(vendor)
    initVendorVersion(vendor.vendorId)
    return mockDelay({ data: vendor, etag: "1" })
  },

  update(vendorId: number, request: UpdateVendorRequest, ifMatch: string): Promise<ApiResult<Vendor>> {
    const v = mockVendors.find((x) => x.vendorId === vendorId)
    if (!v) return Promise.reject(new Error(`Mock vendor ${vendorId} not found`))

    if (String(getVendorVersion(vendorId)) !== ifMatch) {
      return Promise.reject(
        Object.assign(new Error("The vendor was modified by another request."), { code: "CONCURRENCY_CONFLICT" })
      )
    }

    const code = request.code.trim()
    if (!code) return Promise.reject(new Error("Vendor code is required."))
    if (codeTaken(code, vendorId)) {
      return Promise.reject(Object.assign(new Error(`Vendor code "${code}" already exists.`), { code: "SKU_DUPLICATE" }))
    }

    v.code = code
    v.name = request.name.trim()
    v.terms = request.terms?.trim() || null
    v.taxReg = request.taxReg?.trim() || null
    v.currency = request.currency.trim().toUpperCase()
    v.updatedAt = new Date().toISOString()

    const next = bumpVendorVersion(vendorId)
    return mockDelay({ data: v, etag: String(next) })
  },

  updateStatus(vendorId: number, status: EntityStatus): Promise<void> {
    const v = mockVendors.find((x) => x.vendorId === vendorId)
    if (!v) return Promise.reject(new Error(`Mock vendor ${vendorId} not found`))
    v.status = status
    v.updatedAt = new Date().toISOString()
    bumpVendorVersion(vendorId)
    return mockDelay(undefined)
  },
}
