import { type User } from 'src/types/user';

import { type ApproverStepItem, type PotentialApprover } from './types';

const deduplicateApproversById = (list: Array<User | PotentialApprover>) => {
  const seen = new Set<number>();
  const out: Array<User | PotentialApprover> = [];
  for (const item of list) {
    if (seen.has(item.id)) continue;
    seen.add(item.id);
    out.push(item);
  }
  return out;
};

const collectApproversForStep = (step: ApproverStepItem) => {
  const list: Array<User | PotentialApprover> = [];
  if (step.approver) {
    list.push(step.approver);
  }
  if (step.potentialApprovers?.length) {
    list.push(...step.potentialApprovers);
  }
  return deduplicateApproversById(list);
};

/**
 * Responsibles for the summary row: if there is any `rejected` step, the earliest
 * rejected step (by position) is used; for that step only the acting `approver`
 * is shown (resolved rejection), with a fallback to assignees/potentials if the
 * API omits `approver`. Otherwise the current actionable step (`pending`) shows
 * its assignee and/or potential approvers. If neither exists, the last step is
 * used: when it is already approved or rejected, only that step’s `approver`
 * (who participated in the outcome); otherwise potential approvers and assignee
 * as for an open step.
 */
export const getResponsiblesForCurrentApprovalStep = (
  steps: ApproverStepItem[],
) => {
  if (steps.length === 0) {
    return { count: 0, approvers: [] as Array<User | PotentialApprover> };
  }

  const rejectedCandidates = steps.filter(s => s.state === 'rejected');
  if (rejectedCandidates.length > 0) {
    const rejectedStep = rejectedCandidates.reduce((earliest, step) =>
      step.position < earliest.position ? step : earliest,
    );
    const approvers = rejectedStep.approver
      ? [rejectedStep.approver]
      : collectApproversForStep(rejectedStep);
    return { count: approvers.length, approvers };
  }

  const pendingStep = steps.find(s => s.state === 'pending');
  if (pendingStep) {
    const approvers = collectApproversForStep(pendingStep);
    return { count: approvers.length, approvers };
  }

  const lastStep = steps[steps.length - 1];
  const fromLast: Array<User | PotentialApprover> = [];
  const lastStepResolved =
    lastStep.state === 'approved' || lastStep.state === 'rejected';

  if (lastStepResolved) {
    if (lastStep.approver) {
      fromLast.push(lastStep.approver);
    }
  } else {
    if (lastStep.potentialApprovers?.length) {
      fromLast.push(...lastStep.potentialApprovers);
    }
    if (fromLast.length === 0 && lastStep.approver) {
      fromLast.push(lastStep.approver);
    }
  }
  return {
    count: fromLast.length,
    approvers: deduplicateApproversById(fromLast),
  };
};
