/**
 * 与后端 {@link App\Services\Ticket\NumberNormalizer} 对齐的输入长度与金额语义提示。
 */

export type TicketNumberSpec = {
  maxChars: number;
  mode: "digits" | "roll";
};

const PLAY_3D = new Set(["pos_3a", "pos_3b", "pos_3c", "pos_3abc"]);
const PLAY_2D = new Set(["pos_2a", "pos_2b", "pos_2c", "pos_2abc"]);

export function ticketNumberSpec(playCode: string): TicketNumberSpec {
  if (playCode === "roll") {
    return { maxChars: 4, mode: "roll" };
  }
  if (PLAY_3D.has(playCode)) {
    return { maxChars: 3, mode: "digits" };
  }
  if (PLAY_2D.has(playCode)) {
    return { maxChars: 2, mode: "digits" };
  }
  if (
    playCode === "head" ||
    playCode === "tail" ||
    playCode === "odd" ||
    playCode === "even" ||
    playCode === "digit_big" ||
    playCode === "digit_small"
  ) {
    return { maxChars: 1, mode: "digits" };
  }
  return { maxChars: 4, mode: "digits" };
}

export function playNeedsDimension(playCode: string): boolean {
  return (
    playCode === "odd" ||
    playCode === "even" ||
    playCode === "digit_big" ||
    playCode === "digit_small"
  );
}

export function playNeedsDigitSlot(playCode: string): boolean {
  return playCode === "digit_big" || playCode === "digit_small";
}

/** 与后端 {@link App\Services\Ticket\NumberNormalizer::normalizeRoll} 一致：4 位且至少含一个 R。 */
export function isValidRollNumber(value: string): boolean {
  const trimmed = value.trim().toUpperCase();
  return (
    trimmed.length === 4
    && /^[0-9R]+$/.test(trimmed)
    && trimmed.includes("R")
  );
}

export type DraftLineIssueReason = "invalid_number_length" | "roll_requires_r" | "missing_digit_slot";

/**
 * 某玩法列已填金额但无法组成合法注单行时返回原因；合法则返回 null。
 */
export function draftLineIssueReason(
  playCode: string,
  displayNumber: string,
  digitSlot?: number,
): DraftLineIssueReason | null {
  const normalized = normalizeNumberForPlay(displayNumber, playCode);
  const spec = ticketNumberSpec(playCode);
  if (normalized.length !== spec.maxChars) {
    return "invalid_number_length";
  }
  if (playCode === "roll" && !isValidRollNumber(normalized)) {
    return "roll_requires_r";
  }
  if (playNeedsDigitSlot(playCode) && digitSlot === undefined) {
    return "missing_digit_slot";
  }

  return null;
}

function normalizeNumberForPlay(number: string, playCode: string): string {
  if (playCode.startsWith("pos_2")) return number.slice(-2);
  if (playCode.startsWith("pos_3")) return number.slice(-3);
  if (
    playCode === "head"
    || playCode === "tail"
    || playCode === "odd"
    || playCode === "even"
    || playCode === "digit_big"
    || playCode === "digit_small"
  ) {
    return number.slice(-1);
  }
  return number.toUpperCase();
}

/** 产品文档：iBox/Roll 单注金额；mBox 总金额摊分 */
export function ticketAmountHint(
  playCode: string,
  t?: (key: string) => string,
): string {
  if (playCode === "ibox" || playCode === "roll") {
    return (
      t?.("hall.amountHint.iboxRoll") ??
      "本玩法金额为「单注金额」，系统按展开组合数计算总下注与实扣。"
    );
  }
  if (playCode === "mbox") {
    return (
      t?.("hall.amountHint.mbox") ??
      "本玩法金额为「总输入金额」，将均摊到各排列组合（向下取整到最小单位）。"
    );
  }
  return (
    t?.("hall.amountHint.default") ??
    "金额为该笔注单的下注额（最小货币单位整数，与钱包一致）。"
  );
}
