import { describe, it, expect } from 'vitest';
import { computeDealHealth } from '@/lib/services/deal-health';

const daysAgo = (n: number): string => new Date(Date.now() - n * 86_400_000).toISOString();

describe('computeDealHealth', () => {
  it('returns baseline 50 + warm pulse when no signals fire', () => {
    const r = computeDealHealth({ pipelineStage: 'enquiry' });
    expect(r.score).toBe(50);
    expect(r.pulse).toBe('warm');
    expect(r.signals).toEqual([]);
  });

  it('returns neutral baseline when interest is closed/won', () => {
    const r = computeDealHealth({
      pipelineStage: 'contract',
      outcome: 'won',
      dateLastContact: daysAgo(2),
    });
    expect(r.score).toBe(50);
    expect(r.signals).toEqual([]);
  });

  it('returns neutral baseline when interest is archived', () => {
    const r = computeDealHealth({
      pipelineStage: 'eoi',
      archivedAt: daysAgo(10),
      dateLastContact: daysAgo(2),
    });
    expect(r.signals).toEqual([]);
  });

  it('+20 for contact in last 7 days', () => {
    const r = computeDealHealth({
      pipelineStage: 'enquiry',
      dateLastContact: daysAgo(3),
    });
    const sig = r.signals.find((s) => s.id === 'contact_recent');
    expect(sig?.delta).toBe(20);
    expect(r.score).toBeGreaterThanOrEqual(70);
    expect(r.pulse).toBe('hot');
  });

  it('+10 for contact within 14 days', () => {
    const r = computeDealHealth({
      pipelineStage: 'enquiry',
      dateLastContact: daysAgo(10),
    });
    const sig = r.signals.find((s) => s.id === 'contact_warm');
    expect(sig?.delta).toBe(10);
  });

  it('-15 when no contact in 30+ days', () => {
    const r = computeDealHealth({
      pipelineStage: 'qualified',
      dateLastContact: daysAgo(40),
    });
    const sig = r.signals.find((s) => s.id === 'contact_stale');
    expect(sig?.delta).toBe(-15);
  });

  it('-10 when EOI sent >14d ago and still unsigned', () => {
    const r = computeDealHealth({
      pipelineStage: 'eoi',
      dateEoiSent: daysAgo(20),
      eoiDocStatus: 'sent',
    });
    const sig = r.signals.find((s) => s.id === 'eoi_awaiting');
    expect(sig?.delta).toBe(-10);
  });

  it('does NOT penalize EOI awaiting when sub-status is signed', () => {
    const r = computeDealHealth({
      pipelineStage: 'eoi',
      dateEoiSent: daysAgo(20),
      eoiDocStatus: 'signed',
    });
    expect(r.signals.find((s) => s.id === 'eoi_awaiting')).toBeUndefined();
  });

  it('-10 when reservation signed >21d ago but no deposit', () => {
    const r = computeDealHealth({
      pipelineStage: 'reservation',
      dateReservationSigned: daysAgo(25),
    });
    const sig = r.signals.find((s) => s.id === 'deposit_pending');
    expect(sig?.delta).toBe(-10);
  });

  it('does NOT penalize deposit_pending when deposit already received', () => {
    const r = computeDealHealth({
      pipelineStage: 'deposit_paid',
      dateReservationSigned: daysAgo(25),
      dateDepositReceived: daysAgo(2),
    });
    expect(r.signals.find((s) => s.id === 'deposit_pending')).toBeUndefined();
  });

  it('stage progress bonus caps at +30', () => {
    const r = computeDealHealth({
      pipelineStage: 'contract',
      contractDocStatus: 'signed',
    });
    const sig = r.signals.find((s) => s.id === 'stage_progress');
    expect(sig?.delta).toBeLessThanOrEqual(30);
    expect(sig?.delta).toBeGreaterThan(0);
  });

  it('-10 for deals stuck pre-EOI for 30+ days', () => {
    const r = computeDealHealth({
      pipelineStage: 'enquiry',
      dateFirstContact: daysAgo(45),
    });
    const sig = r.signals.find((s) => s.id === 'stuck_top_funnel');
    expect(sig?.delta).toBe(-10);
  });

  it('clamps score to [0, 100]', () => {
    const r = computeDealHealth({
      pipelineStage: 'contract',
      dateLastContact: daysAgo(2),
      contractDocStatus: 'signed',
    });
    expect(r.score).toBeLessThanOrEqual(100);
    expect(r.score).toBeGreaterThanOrEqual(0);
  });

  it('rates a fresh contract-signed deal as hot', () => {
    const r = computeDealHealth({
      pipelineStage: 'contract',
      dateLastContact: daysAgo(1),
      contractDocStatus: 'signed',
    });
    expect(r.pulse).toBe('hot');
  });

  it('rates a stalled mid-funnel deal with no recent contact as cold', () => {
    const r = computeDealHealth({
      pipelineStage: 'qualified',
      dateFirstContact: daysAgo(60),
      dateLastContact: daysAgo(45),
    });
    expect(r.pulse).toBe('cold');
  });

  it('+5 active_engagement when recentActivityCount >= 1', () => {
    const r = computeDealHealth({
      pipelineStage: 'enquiry',
      recentActivityCount: 3,
    });
    const sig = r.signals.find((s) => s.id === 'active_engagement');
    expect(sig?.delta).toBe(5);
  });

  it('skips active_engagement when recentActivityCount is null/undefined', () => {
    const r = computeDealHealth({
      pipelineStage: 'enquiry',
      recentActivityCount: null,
    });
    expect(r.signals.find((s) => s.id === 'active_engagement')).toBeUndefined();
  });

  it('skips active_engagement when recentActivityCount is 0', () => {
    const r = computeDealHealth({
      pipelineStage: 'enquiry',
      recentActivityCount: 0,
    });
    expect(r.signals.find((s) => s.id === 'active_engagement')).toBeUndefined();
  });
});
