import { Cluster } from "../types";

import { clusterSelector } from "./selectorsHelpers";

type Constraints = NonNullable<Cluster["constraints"]>;

type ExtractConstraint<GROUP extends keyof Constraints, SHAPE> = Extract<
  NonNullable<Constraints[GROUP]>[number],
  SHAPE
>;

type LocationNode = ExtractConstraint<"rsc_location", { node: string }>;
type LocationRule = ExtractConstraint<"rsc_location", { rule_string: string }>;
type ColocationPair = ExtractConstraint<"rsc_colocation", { rsc: string }>;
type ColocationSet = ExtractConstraint<"rsc_colocation", { sets: unknown }>;
type OrderPair = ExtractConstraint<"rsc_order", { first: string }>;
type OrderSet = ExtractConstraint<"rsc_order", { sets: unknown }>;
type TicketResource = ExtractConstraint<"rsc_ticket", { rsc: string }>;
type TicketSet = ExtractConstraint<"rsc_ticket", { sets: unknown }>;

export type ConstraintPack =
  | { type: "Location"; constraint: LocationNode }
  | { type: "Location (rule)"; constraint: LocationRule }
  | { type: "Colocation"; constraint: ColocationPair }
  | { type: "Colocation (set)"; constraint: ColocationSet }
  | { type: "Order"; constraint: OrderPair }
  | { type: "Order (set)"; constraint: OrderSet }
  | { type: "Ticket"; constraint: TicketResource }
  | { type: "Ticket (set)"; constraint: TicketSet };

export const getConstraints = clusterSelector((clusterStatus) => {
  const constraintMap = clusterStatus.constraints;
  if (!constraintMap) {
    return [];
  }
  const locationsNode: ConstraintPack[] = (
    constraintMap.rsc_location || []
  ).map(constraint =>
    "node" in constraint
      ? { type: "Location", constraint }
      : { type: "Location (rule)", constraint },
  );

  const colocations: ConstraintPack[] = (
    constraintMap.rsc_colocation || []
  ).map(constraint =>
    "sets" in constraint
      ? { type: "Colocation (set)", constraint }
      : { type: "Colocation", constraint },
  );

  const orders: ConstraintPack[] = (constraintMap.rsc_order || []).map(
    constraint =>
      "sets" in constraint
        ? { type: "Order (set)", constraint }
        : { type: "Order", constraint },
  );

  const tickets: ConstraintPack[] = (constraintMap.rsc_ticket || []).map(
    constraint =>
      "sets" in constraint
        ? { type: "Ticket (set)", constraint }
        : { type: "Ticket", constraint },
  );

  return [...locationsNode, ...colocations, ...orders, ...tickets];
});
