import { describe, it, expect } from 'vitest';
import {
  computePortfolioHealthScore,
  computeOnTrack,
  computeScheduleVariance,
  buildAttentionItems,
  classifyPortfolioHealth,
  blockedTrend,
  formatHealthTrendLabel,
  resolvePortfolioHealthTrend,
} from '@/features/projects/utils/portfolioMetrics';
import type { PortfolioTimelineRow } from '@/features/projects/types/project.types';

const baseRow: PortfolioTimelineRow = {
  id: 'project-p1',
  project_id: 'p1',
  title: 'Owner Portal',
  owner: 'Alex',
  department: 'IT',
  start_date: '2026-01-01',
  end_date: '2027-06-01',
  planned_start_date: '2026-01-01',
  planned_end_date: '2027-06-01',
  actual_start_date: null,
  actual_end_date: null,
  progress_percentage: 50,
  status: 'active',
  health: 'healthy',
  current_sprint: null,
  next_milestone: null,
  delayed_milestones_count: 0,
  milestones_count: 1,
  open_risks_count: 0,
  blocked_dependencies_count: 0,
  is_delayed: false,
  is_blocked: false,
  is_at_risk: false,
  milestones: [],
};

const labels = {
  delayed: (count: number) => `${count} days late`,
  blocked: 'Blocked by dependency',
  atRisk: 'Health deteriorating',
  milestoneMissed: 'Milestone missed',
  criticalDependency: 'Critical dependency',
  risks: (count: number) => `${count} open risks`,
};

describe('portfolioMetrics', () => {
  it('classifies portfolio health score bands', () => {
    expect(classifyPortfolioHealth(95)).toBe('excellent');
    expect(classifyPortfolioHealth(80)).toBe('healthy');
    expect(classifyPortfolioHealth(65)).toBe('at_risk');
    expect(classifyPortfolioHealth(40)).toBe('critical');
  });

  it('computes on track excluding blocked projects', () => {
    expect(
      computeOnTrack({
        total_projects: 10,
        active_projects: 8,
        completed_projects: 1,
        delayed_projects: 2,
        blocked_projects: 1,
        at_risk_projects: 1,
      }),
    ).toBe(5);
  });

  it('computes portfolio health from rows and summary', () => {
    const result = computePortfolioHealthScore([baseRow], {
      total_projects: 1,
      active_projects: 1,
      completed_projects: 0,
      delayed_projects: 0,
      blocked_projects: 0,
      at_risk_projects: 0,
    });

    expect(result.score).toBeGreaterThanOrEqual(75);
    expect(result.classification).toBe('excellent');
  });

  it('reports delayed schedule variance', () => {
    const variance = computeScheduleVariance({
      ...baseRow,
      is_delayed: true,
      end_date: '2020-01-01',
      planned_end_date: '2020-01-01',
    });

    expect(variance.type).toBe('delayed');
    expect(variance.days).toBeGreaterThan(0);
  });

  it('reports on schedule when not delayed', () => {
    const variance = computeScheduleVariance({
      ...baseRow,
      progress_percentage: 20,
    });
    expect(variance.type).toBe('on_schedule');
  });

  it('builds attention required items sorted by severity', () => {
    const rows: PortfolioTimelineRow[] = [
      baseRow,
      {
        ...baseRow,
        id: 'project-p2',
        project_id: 'p2',
        title: 'Benefits Platform',
        is_blocked: true,
        blocked_dependencies_count: 2,
      },
      {
        ...baseRow,
        id: 'project-p3',
        project_id: 'p3',
        title: 'Contractor Management',
        is_delayed: true,
        end_date: '2020-01-01',
        planned_end_date: '2020-01-01',
      },
    ];

    const items = buildAttentionItems(rows, labels);
    expect(items.length).toBeGreaterThan(0);
    expect(items[0].project).toBe('Benefits Platform');
    expect(items[0].category).toBe('blocked');
    expect(items[0].priorityScore).toBeGreaterThanOrEqual(50);
    expect(items.some((item) => item.project === 'Contractor Management')).toBe(true);
    expect(items.length).toBeLessThanOrEqual(5);
  });

  it('resolves health trend from API summary snapshot', () => {
    const trend = resolvePortfolioHealthTrend({
      total_projects: 1,
      active_projects: 1,
      completed_projects: 0,
      delayed_projects: 0,
      blocked_projects: 0,
      at_risk_projects: 0,
      health_trend: {
        previous_score: 72,
        trend_percent: 6,
        direction: 'up',
      },
    });

    expect(trend.previousScore).toBe(72);
    expect(trend.trendPercent).toBe(6);
    expect(trend.trend).toBe('up');
    expect(
      formatHealthTrendLabel(
        { previous_score: 72, trend_percent: 6, direction: 'up' },
        (key, opts) => `${opts?.sign} ${opts?.percent}% vs last month`,
      ),
    ).toContain('6%');
  });

  it('detects blocked trend when threshold exceeded', () => {
    expect(
      blockedTrend({
        total_projects: 10,
        active_projects: 8,
        completed_projects: 0,
        delayed_projects: 0,
        blocked_projects: 3,
        at_risk_projects: 0,
      }),
    ).toBe('up');
  });
});
