import { describe, expect, it } from 'vitest';
import { readFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';
import { localMeta } from '../_lib/local-meta.js';
import createConnector, { gradeToken, parseCategories, parseSeriesPage, parseYearMint, updatedDate } from './index.js';
const dir = path.dirname(fileURLToPath(import.meta.url));
const connector = createConnector(localMeta(JSON.parse(readFileSync(path.join(dir, 'meta.json'), 'utf8'))));
const PAGE = `
`;
describe('ngc-priceguide', () => {
runFixtureSuite(connector, it, expect);
it('parses categories JSON into subcategories', () => {
const subs = parseCategories([{ CategoryID: 14, Name: 'Dollars', SeoName: 'dollars', Subcategories: [{ SubcategoryID: 49, Name: 'Morgan Dollars (1878-1921)', SubcategorySeoName: 'morgan-dollars-1878-1921', HasMS: true, HasPF: true }] }]);
expect(subs).toEqual([{ id: '49', name: 'Morgan Dollars (1878-1921)', categorySeo: 'dollars', categoryName: 'Dollars' }]);
expect(parseCategories({ nope: 1 })).toEqual([]);
});
it('parses a series page: coin rows joined with price cells by coin id', () => {
const p = parseSeriesPage(PAGE, 'https://www.ngccoin.com/price-guide/united-states/dollars/49/', 'dollars')!;
expect(p.seriesName).toBe('Morgan Dollars (1878-1921)');
expect(p.subcategoryId).toBe('49');
expect(p.coins.length).toBe(3);
expect(p.coins[0]).toMatchObject({ coinId: '17072', yearMint: '1878 8TF', description: '1878 8TF $1 MS', denomination: '$1', designation: 'MS', strike: 'ms', updatedText: '9/8/2026' });
expect(p.coins[0]!.prices).toEqual({ PrAg: 59, VF: 100, 'XF+': 135, '65': 2350, '65+': 3000, '66★': 9000 });
expect(p.coins[1]).toMatchObject({ strike: 'pf', designation: 'PF', prices: { '63': 8500 } });
expect(p.coins[2]!.updatedText).toBeNull();
});
it('helpers: dates, year/mint, grade tokens', () => {
expect(updatedDate('9/8/2026')?.toISOString()).toBe('2026-09-08T00:00:00.000Z');
expect(updatedDate(null)).toBeNull();
expect(parseYearMint('1878 8TF')).toEqual({ year: 1878, mintMark: null, variety: '8TF' });
expect(parseYearMint('1893-S')).toEqual({ year: 1893, mintMark: 'S', variety: null });
expect(gradeToken('65', 'MS', 'ms')).toBe('MS65');
expect(gradeToken('65+', 'MS', 'ms')).toBe('MS65+');
expect(gradeToken('63', 'PF', 'pf')).toBe('PF63');
expect(gradeToken('66★', 'MS', 'ms')).toBe('MS66★');
expect(gradeToken('XF+', 'MS', 'ms')).toBe('XF+');
expect(gradeToken('PrAg', 'MS', 'ms')).toBe('PrAg');
expect(gradeToken('65', 'MSDPL', 'ms')).toBe('MS65');
});
it('normalises catalog items + dated guide observations; rows without an Updated date are dropped', async () => {
const p = parseSeriesPage(PAGE, 'https://www.ngccoin.com/price-guide/united-states/dollars/49/', 'dollars')!;
const out = await connector.normalize({ url: p.url, externalId: 'x', kind: 'price_observation', engine: 'api', fetchedAt: new Date('2026-09-08T12:00:00Z'), payload: p });
const items = out.filter((r) => r.kind === 'catalog_item');
const obs = out.filter((r) => r.kind === 'price_observation');
expect(items.length).toBe(2); // 1893-S has no Updated date → skipped
expect(obs.length).toBe(7);
const o = obs.find((r) => r.kind === 'price_observation' && r.grade.grade === 'PrAg')!;
if (o.kind !== 'price_observation') throw new Error('obs');
expect(o).toMatchObject({ priceKind: 'guide_value', price: 59, currency: 'USD', grade: { grader: 'ngc', grade: 'PrAg' } });
expect(o.observationDate.toISOString()).toBe('2026-09-08T00:00:00.000Z');
expect(o.attributes).toMatchObject({ categorySlug: 'coins', year: 1878, country: 'US', series: 'Morgan Dollars (1878-1921)', identifiers: { ngc_coin_id: '17072' }, variant: '8TF' });
const ms65 = obs.find((r) => r.kind === 'price_observation' && r.grade.grade === 'MS65');
expect(ms65 && ms65.kind === 'price_observation' ? ms65.price : null).toBe(2350);
const pf = obs.find((r) => r.kind === 'price_observation' && r.grade.grade === 'PF63');
expect(pf && pf.kind === 'price_observation' ? pf.observationDate.toISOString() : null).toBe('2025-01-24T00:00:00.000Z');
});
it('fixtures: Morgan dollars and Walking Liberty halves', async () => {
for (const name of ['series-morgan-dollars-49', 'series-walking-liberty-halves-42']) {
const out = await connector.normalize(loadFixture('ngc-priceguide', name).raw);
expect(out.some((r) => r.kind === 'price_observation' && r.grade.grader === 'ngc')).toBe(true);
for (const r of out) if (r.kind === 'price_observation') expect(r.currency).toBe('USD');
}
});
});