/**
 * Минимальный mock MoySklad JSON-API 1.2 для e2e-теста импорта.
 *
 * Отдаёт ровно те эндпоинты, которые дёргает MoySkladClient:
 *   GET entity/organization   — для test-connection (WhoAmI)
 *   GET entity/counterparty   — список контрагентов
 *   GET entity/product        — список товаров
 *   GET entity/productfolder  — группы товаров
 *
 * Формы JSON повторяют реальные поля API (см. MoySkladDtos.cs): name,
 * legalTitle, companyType, inn, kpp, phone, email, actual/legalAddress,
 * description, archived; product.name/article/code/weighed/vat/vatEnabled/
 * trackingType/barcodes/salePrices/buyPrice/productFolder/country. Значения в
 * деньгах — в minor units (как у MoySklad: клиент делит на 100).
 *
 * Пагинация: данных мало (<1000), поэтому клиент забирает всё одной страницей.
 * Запрос с filter=archived=true отдаём пустым (все наши записи активны).
 *
 * Данные мутабельны (setData) — между прогонами импорта меняем их, чтобы
 * проверить overwrite/идемпотентность.
 */
import { createServer, type Server } from 'node:http'

export interface MsDataset {
  organization: { name: string; inn: string }
  counterparties: Record<string, unknown>[]
  products: Record<string, unknown>[]
  folders: Record<string, unknown>[]
}

export interface MockHandle {
  baseUrl: string
  setData: (d: MsDataset) => void
  requestCount: () => number
  close: () => Promise<void>
}

const BASE_PATH = '/api/remap/1.2/'

export function startMoySkladMock(port: number): Promise<MockHandle> {
  let data: MsDataset = { organization: { name: 'Mock Org', inn: '000000000000' }, counterparties: [], products: [], folders: [] }
  let requests = 0

  const listBody = (rows: Record<string, unknown>[]) => JSON.stringify({
    meta: { size: rows.length, limit: 1000, offset: 0, href: 'mock' },
    rows,
  })

  const server = createServer((req, res) => {
    requests++
    const url = req.url ?? ''
    const archivedOnly = url.includes('archived=true')
    const path = url.split('?')[0]

    const send = (rows: Record<string, unknown>[]) => {
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(listBody(archivedOnly ? [] : rows))
    }

    if (!path.startsWith(BASE_PATH)) {
      res.writeHead(404, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({ errors: [{ error: 'not found', code: 0 }] }))
      return
    }
    const entity = path.slice(BASE_PATH.length)

    switch (entity) {
      case 'entity/organization':
        res.writeHead(200, { 'Content-Type': 'application/json' })
        res.end(listBody([data.organization as Record<string, unknown>]))
        return
      case 'entity/counterparty': return send(data.counterparties)
      case 'entity/product': return send(data.products)
      case 'entity/productfolder': return send(data.folders)
      default:
        res.writeHead(404, { 'Content-Type': 'application/json' })
        res.end(JSON.stringify({ errors: [{ error: `unhandled ${entity}`, code: 0 }] }))
    }
  })

  return new Promise((resolve) => {
    server.listen(port, '127.0.0.1', () => {
      resolve({
        baseUrl: `http://127.0.0.1:${port}${BASE_PATH}`,
        setData: (d) => { data = d },
        requestCount: () => requests,
        close: () => new Promise((r) => server.close(() => r())),
      })
    })
  })
}
