import type { Prisma } from '@prisma/client';

const UNION_PINNED_PREFIX = [
  'intraoral_scan',
  'choosing_abutment',
  'design',
  'model_create',
] as const;

const UNION_SUFFIX = ['packing', 'shipping'] as const;

const UNION_PINNED = new Set<string>(UNION_PINNED_PREFIX);
const UNION_TAIL = new Set<string>(UNION_SUFFIX);

/** Remaining manufacturing steps — matches catalog LAB_WORKFLOW_STEPS order. */
const UNION_MIDDLE_ORDER: Record<string, number> = {
  milling_dry: 1,
  milling_wet: 2,
  printer_resin: 3,
  printer_metal: 4,
  pressing: 5,
  sinter: 6,
  build_up: 7,
  stain: 8,
  glaze: 9,
  polish_prep: 10,
};

/** Union stacked workflows: pin scan → abutment → design → model, then catalog order, pack/ship last. */
export function unionWorkflowStepCodes(lists: readonly (readonly string[])[]): string[] {
  const present = new Set<string>();
  for (const list of lists) {
    for (const code of list) {
      if (code) present.add(code);
    }
  }

  const out: string[] = [];
  for (const code of UNION_PINNED_PREFIX) {
    if (present.has(code)) out.push(code);
  }

  const middle = [...present].filter((code) => !UNION_PINNED.has(code) && !UNION_TAIL.has(code));
  middle.sort((a, b) => {
    const da = UNION_MIDDLE_ORDER[a] ?? 100;
    const db = UNION_MIDDLE_ORDER[b] ?? 100;
    if (da !== db) return da - db;
    return a.localeCompare(b);
  });
  out.push(...middle);

  for (const code of UNION_SUFFIX) {
    if (present.has(code)) out.push(code);
  }
  return out;
}

export function prosthesisGroupKey(codes: readonly string[]): string {
  return [...new Set(codes.filter(Boolean))].sort().join('+');
}

export function splitProsthesisGroupKey(key: string): string[] {
  return key.split('+').map((part) => part.trim()).filter(Boolean);
}

export function prosthesisTypeTaskWhere(code: string): Prisma.LabCaseTaskWhereInput {
  return {
    OR: [
      { prosthesisTypeCode: code },
      { prosthesisTypeCode: { startsWith: `${code}+` } },
      { prosthesisTypeCode: { endsWith: `+${code}` } },
      { prosthesisTypeCode: { contains: `+${code}+` } },
    ],
  };
}

export function prosthesisTypeCaseWhere(code: string): Prisma.LabCaseWhereInput {
  return {
    OR: [
      { toothProsthesis: { some: { prosthesisTypeCode: code } } },
      { tasks: { some: prosthesisTypeTaskWhere(code) } },
    ],
  };
}

export function atomicProsthesisCodes(codes: Iterable<string>): string[] {
  const out = new Set<string>();
  for (const code of codes) {
    if (!code) continue;
    for (const part of splitProsthesisGroupKey(code)) out.add(part);
  }
  return [...out];
}

export function prosthesisGroupLabel(
  groupKey: string,
  labels: ReadonlyMap<string, string>,
): string {
  const parts = splitProsthesisGroupKey(groupKey);
  if (parts.length === 0) return groupKey;
  return parts.map((code) => labels.get(code) ?? code).join(' + ');
}
