import { describe, expect, it } from 'vitest';
import {
  buildReferenceResearchQuery,
  createShortlistItem,
  findProbableMissingDoi,
  migrateShortlistRecords,
  parseBibTeX,
  rankReferenceResearchCandidates,
  researchFiltersForIntent,
  type ReferenceRecord,
} from '../index';

const records: ReferenceRecord[] = [
  {
    id: 's2:new',
    provider: 'semantic-scholar',
    providerId: 'new',
    title: 'Robust browser local scientific editing improves reproducibility',
    abstractText: 'We demonstrate robust browser local scientific editing and improved reproducibility.',
    authors: ['Ada Researcher'],
    year: 2026,
    citationCount: 20,
  },
  {
    id: 'oa:old',
    provider: 'openalex',
    providerId: 'old',
    title: 'Scientific editing and reproducibility',
    abstractText: 'An early study of reproducibility in scientific editing.',
    authors: ['Grace Scholar'],
    year: 2004,
    citationCount: 2400,
  },
  {
    id: 's2:challenge',
    provider: 'semantic-scholar',
    providerId: 'challenge',
    title: 'Challenges to browser local reproducibility claims',
    abstractText: 'However, we find no evidence that browser local editing improves reproducibility in this setting.',
    authors: ['Lin Reviewer'],
    year: 2025,
    citationCount: 44,
  },
];

describe('R14.25.1 research assistance', () => {
  it('uses intent-specific deterministic ranking without asserting that metadata proves a claim', () => {
    const query = 'browser local scientific editing improves reproducibility';
    const recent = rankReferenceResearchCandidates(records, query, 'recent', 2026);
    expect(recent[0]?.record.id).toBe('s2:new');

    const seminal = rankReferenceResearchCandidates(records, query, 'seminal', 2026);
    expect(seminal[0]?.record.id).toBe('oa:old');

    const contradicting = rankReferenceResearchCandidates(records, query, 'contradicting', 2026);
    expect(contradicting[0]?.record.id).toBe('s2:challenge');
    expect(contradicting[0]?.requiresFullTextVerification).toBe(true);
    expect(contradicting[0]?.reasons.join(' ')).toMatch(/candidate contradicting source/i);
  });

  it('builds a compact technical provider query and rejects recent unrelated metadata dumps', () => {
    const claim = String.raw`In this work, we adapted and re-implemented a graph-based clustering algorithm known as MST$k$NN, proposed in Inostroza-Ponta \cite{Mariothesis2008}, using a minimum spanning tree and k-nearest neighbor proximity graph.`;
    const providerQuery = buildReferenceResearchQuery(claim);
    expect(providerQuery).toMatch(/MSTkNN/u);
    expect(providerQuery).toMatch(/clustering/u);
    expect(providerQuery).toMatch(/Inostroza-Ponta/u);
    expect(providerQuery).not.toMatch(/Mariothesis2008|\\cite/u);

    const candidates: ReferenceRecord[] = [
      {
        id: 'relevant-old', provider: 'openalex', providerId: 'relevant-old',
        title: 'Clustering complex networks using a minimum spanning tree and nearest-neighbor graph',
        abstractText: 'A graph clustering method based on minimum spanning tree and k-nearest neighbor proximity graphs.',
        authors: ['M. Inostroza-Ponta'], year: 2008, citationCount: 90,
      },
      {
        id: 'recent-cpec', provider: 'crossref', providerId: 'recent-cpec',
        title: 'Cultural implications of the China Pakistan Economic Corridor',
        abstractText: 'This study presents results and a research approach concerning political and economic relations in Pakistan.',
        authors: ['Unrelated Author'], year: 2025, citationCount: 5,
      },
      {
        id: 'issue-dump', provider: 'crossref', providerId: 'issue-dump',
        title: 'Volume 2 Issue 4 ' + 'unrelated journal index '.repeat(40),
        abstractText: 'study results data research method '.repeat(1000),
        authors: [], year: 2026,
      },
    ];
    const ranked = rankReferenceResearchCandidates(candidates, providerQuery, 'recent', 2026);
    expect(ranked.map((item) => item.record.id)).toEqual(['relevant-old']);
  });

  it('maps recent and seminal intent onto provider sorts', () => {
    expect(researchFiltersForIntent({}, 'recent').sort).toBe('newest');
    expect(researchFiltersForIntent({}, 'seminal').sort).toBe('most-cited');
    expect(researchFiltersForIntent({ sort: 'relevance' }, 'related').sort).toBe('relevance');
  });

  it('only proposes missing DOI metadata for a strong title/author/year match', () => {
    const entry = parseBibTeX(`@article{browser2025,
  title = {Browser Local Scientific Editing},
  author = {Researcher, Ada and Scholar, Grace},
  year = {2025}
}`).entries[0]!;
    const match = findProbableMissingDoi(entry, [
      {
        id: 'crossref:1',
        provider: 'crossref',
        providerId: '1',
        title: 'Browser Local Scientific Editing',
        authors: ['Ada Researcher'],
        year: 2025,
        doi: '10.1000/browser-local',
      },
      {
        id: 'crossref:2',
        provider: 'crossref',
        providerId: '2',
        title: 'A Different Scientific Editing Paper',
        authors: ['Someone Else'],
        year: 2025,
        doi: '10.1000/different',
      },
    ]);
    expect(match?.doi).toBe('10.1000/browser-local');
    expect(match?.confidence).toBeGreaterThanOrEqual(0.86);
  });

  it('migrates the R14.25.0 shortlist into explicit candidate state', () => {
    const legacy = records.slice(0, 1);
    const migrated = migrateShortlistRecords(legacy, 1000);
    expect(migrated).toHaveLength(1);
    expect(migrated[0]?.state).toBe('candidate');
    expect(migrated[0]?.addedAt).toBe(1000);

    const included = { ...createShortlistItem(records[1]!, 1000), state: 'included' as const, notes: 'keep' };
    expect(migrateShortlistRecords([included], 2000)[0]).toMatchObject({ state: 'included', notes: 'keep', addedAt: 1000 });
  });
});
