import type { CrossProjectDependency } from '@/features/projects/types/project.types';

export type DependencyRisk = 'overdue' | 'due_soon' | 'open' | 'resolved';

export interface ProjectExposure {
  projectId: string;
  projectName: string;
  inbound: number;
  outbound: number;
  total: number;
}

export interface PortfolioDependencyAnalytics {
  total: number;
  open: number;
  resolved: number;
  atRisk: number;
  overdue: number;
  dueSoon: number;
  uniqueProjects: number;
  byStatus: Array<[string, number]>;
  byType: Array<[string, number]>;
  attentionItems: Array<CrossProjectDependency & { risk: DependencyRisk }>;
  projectExposure: ProjectExposure[];
  upcomingDue: CrossProjectDependency[];
}

const DUE_SOON_DAYS = 14;

function startOfDay(date: Date): Date {
  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}

function daysUntil(dueDate: string, today: Date): number {
  const due = startOfDay(new Date(dueDate));
  return Math.round((due.getTime() - today.getTime()) / 86_400_000);
}

export function classifyDependencyRisk(
  dep: CrossProjectDependency,
  today = startOfDay(new Date()),
): DependencyRisk {
  if (dep.status === 'resolved') return 'resolved';
  if (dep.due_date) {
    const days = daysUntil(dep.due_date, today);
    if (days < 0) return 'overdue';
    if (days <= DUE_SOON_DAYS) return 'due_soon';
  }
  return 'open';
}

function countMap(entries: Iterable<[string, number]>): Array<[string, number]> {
  return [...entries].filter(([, count]) => count > 0).sort((a, b) => b[1] - a[1]);
}

export function analyzePortfolioDependencies(
  dependencies: CrossProjectDependency[],
): PortfolioDependencyAnalytics {
  const today = startOfDay(new Date());
  const statusCounts = new Map<string, number>();
  const typeCounts = new Map<string, number>();
  const exposureMap = new Map<string, ProjectExposure>();
  const projectIds = new Set<string>();

  let open = 0;
  let resolved = 0;
  let overdue = 0;
  let dueSoon = 0;

  const classified = dependencies.map((dep) => ({
    ...dep,
    risk: classifyDependencyRisk(dep, today),
  }));

  for (const dep of classified) {
    statusCounts.set(dep.status, (statusCounts.get(dep.status) ?? 0) + 1);
    typeCounts.set(dep.dependency_type, (typeCounts.get(dep.dependency_type) ?? 0) + 1);

    if (dep.risk === 'resolved') resolved += 1;
    else open += 1;
    if (dep.risk === 'overdue') overdue += 1;
    if (dep.risk === 'due_soon') dueSoon += 1;

    projectIds.add(dep.source_project_id);
    projectIds.add(dep.target_project_id);

    const sourceName = dep.source_project_name ?? dep.source_project_id;
    const targetName = dep.target_project_name ?? dep.target_project_id;

    const source = exposureMap.get(dep.source_project_id) ?? {
      projectId: dep.source_project_id,
      projectName: sourceName,
      inbound: 0,
      outbound: 0,
      total: 0,
    };
    source.outbound += 1;
    source.total += 1;
    exposureMap.set(dep.source_project_id, source);

    const target = exposureMap.get(dep.target_project_id) ?? {
      projectId: dep.target_project_id,
      projectName: targetName,
      inbound: 0,
      outbound: 0,
      total: 0,
    };
    target.inbound += 1;
    target.total += 1;
    exposureMap.set(dep.target_project_id, target);
  }

  const attentionItems = classified
    .filter((dep) => dep.risk === 'overdue' || dep.risk === 'due_soon' || (dep.status !== 'resolved' && dep.notes))
    .sort((a, b) => {
      const rank = { overdue: 0, due_soon: 1, open: 2, resolved: 3 };
      const diff = rank[a.risk] - rank[b.risk];
      if (diff !== 0) return diff;
      if (a.due_date && b.due_date) return a.due_date.localeCompare(b.due_date);
      if (a.due_date) return -1;
      if (b.due_date) return 1;
      return 0;
    });

  const upcomingDue = classified
    .filter((dep) => dep.risk !== 'resolved' && dep.due_date && daysUntil(dep.due_date, today) >= 0)
    .sort((a, b) => (a.due_date ?? '').localeCompare(b.due_date ?? ''))
    .slice(0, 6);

  const projectExposure = [...exposureMap.values()].sort((a, b) => b.total - a.total);

  return {
    total: dependencies.length,
    open,
    resolved,
    atRisk: overdue + dueSoon,
    overdue,
    dueSoon,
    uniqueProjects: projectIds.size,
    byStatus: countMap(statusCounts),
    byType: countMap(typeCounts),
    attentionItems,
    projectExposure,
    upcomingDue,
  };
}

export function filterDependenciesByStatus(
  dependencies: CrossProjectDependency[],
  filter: 'all' | 'open' | 'resolved',
): CrossProjectDependency[] {
  if (filter === 'all') return dependencies;
  if (filter === 'resolved') return dependencies.filter((dep) => dep.status === 'resolved');
  return dependencies.filter((dep) => dep.status !== 'resolved');
}
