import { describe, it, expect } from 'vitest';
import { findContradictions, mergeTriples, isTripleCurrent } from '../kg.js';
import type { TripleInput } from '../kg.js';

const now = new Date('2025-06-01T00:00:00Z');

describe('isTripleCurrent', () => {
  it('returns true for triple with no validTo', () => {
    expect(isTripleCurrent({ validTo: undefined }, now)).toBe(true);
  });

  it('returns true for triple with future validTo', () => {
    expect(isTripleCurrent({ validTo: '2026-01-01T00:00:00Z' }, now)).toBe(true);
  });

  it('returns false for triple with past validTo', () => {
    expect(isTripleCurrent({ validTo: '2024-01-01T00:00:00Z' }, now)).toBe(false);
  });
});

describe('findContradictions', () => {
  it('detects contradiction (same subject+predicate, different object)', () => {
    const existing: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'PostgreSQL', validFrom: '2025-01-01' },
    ];
    const incoming: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'Cosmos DB', validFrom: '2025-06-01' },
    ];
    const result = findContradictions(existing, incoming, now);
    expect(result).toHaveLength(1);
    expect(result[0].existing.object).toBe('PostgreSQL');
    expect(result[0].incoming.object).toBe('Cosmos DB');
  });

  it('does not flag same triple as contradiction', () => {
    const existing: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'Cosmos DB', validFrom: '2025-01-01' },
    ];
    const incoming: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'Cosmos DB', validFrom: '2025-06-01' },
    ];
    expect(findContradictions(existing, incoming, now)).toHaveLength(0);
  });

  it('ignores expired triples', () => {
    const existing: TripleInput[] = [
      {
        subject: 'App',
        predicate: 'uses',
        object: 'PostgreSQL',
        validFrom: '2024-01-01',
        validTo: '2024-12-31',
      },
    ];
    const incoming: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'Cosmos DB', validFrom: '2025-06-01' },
    ];
    expect(findContradictions(existing, incoming, now)).toHaveLength(0);
  });

  it('is case-insensitive', () => {
    const existing: TripleInput[] = [
      { subject: 'app', predicate: 'Uses', object: 'PostgreSQL', validFrom: '2025-01-01' },
    ];
    const incoming: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'Cosmos DB', validFrom: '2025-06-01' },
    ];
    expect(findContradictions(existing, incoming, now)).toHaveLength(1);
  });
});

describe('mergeTriples', () => {
  it('adds non-conflicting triples', () => {
    const existing: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'TypeScript', validFrom: '2025-01-01' },
    ];
    const incoming: TripleInput[] = [
      { subject: 'App', predicate: 'runs-on', object: 'Node.js', validFrom: '2025-06-01' },
    ];
    const result = mergeTriples(existing, incoming, now);
    expect(result.added).toHaveLength(1);
    expect(result.skipped).toHaveLength(0);
    expect(result.invalidated).toHaveLength(0);
    expect(result.merged).toHaveLength(2);
  });

  it('skips duplicate triples', () => {
    const existing: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'TypeScript', validFrom: '2025-01-01' },
    ];
    const incoming: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'TypeScript', validFrom: '2025-06-01' },
    ];
    const result = mergeTriples(existing, incoming, now);
    expect(result.skipped).toHaveLength(1);
    expect(result.added).toHaveLength(0);
  });

  it('invalidates contradicted triples', () => {
    const existing: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'PostgreSQL', validFrom: '2025-01-01' },
    ];
    const incoming: TripleInput[] = [
      { subject: 'App', predicate: 'uses', object: 'Cosmos DB', validFrom: '2025-06-01' },
    ];
    const result = mergeTriples(existing, incoming, now);
    expect(result.invalidated).toHaveLength(1);
    expect(result.added).toHaveLength(1);
    // The invalidated triple should have validTo set
    const invalidated = result.merged.find(t => t.object === 'PostgreSQL');
    expect(invalidated?.validTo).toBeDefined();
  });
});
