import type { Card } from './types';
import {
  cardColor,
  cardPoint,
  isHeart3,
  isJoker,
  pairName,
  singleValue,
} from './cards';

/** 两张组牌的评估结果 */
export interface GroupEval {
  /** 大类排序值（越大越强），用于跨类比较 */
  rank: number;
  /** 牌型名（如 丁皇 / 天牌 / 天杠 / 天关九 / 8点） */
  name: string;
  /** 同类比较用的最大单张值 */
  topSingle: number;
}

// —— 单张判定小工具 ——
function isRedRank(c: Card, rank: string): boolean {
  return cardColor(c) === 'red' && c.rank === rank;
}
function isBlackRank(c: Card, rank: string): boolean {
  return cardColor(c) === 'black' && c.rank === rank;
}
/** 一组里是否同时存在满足 a 和 b 的两张牌（a≠b 时按两张分别匹配） */
function pairMatch(
  cards: [Card, Card],
  a: (c: Card) => boolean,
  b: (c: Card) => boolean,
): boolean {
  const [x, y] = cards;
  return (a(x) && b(y)) || (a(y) && b(x));
}

/** 是否一对（同色同点） */
function asPairValue(cards: [Card, Card]): number | null {
  const [a, b] = cards;
  if (isJoker(a) || isJoker(b) || isHeart3(a) || isHeart3(b)) return null;
  if (a.rank === b.rank && cardColor(a) === cardColor(b)) {
    return singleValue(a);
  }
  return null;
}

/** 两张牌的点数（个位） */
export function groupPoint(cards: [Card, Card]): number {
  return (cardPoint(cards[0]) + cardPoint(cards[1])) % 10;
}

// 9 点牌型分档（tier 越大越强）；返回 [tier, name] 或 null
function nineHand(cards: [Card, Card]): [number, string] | null {
  if (groupPoint(cards) !== 9) return null;
  const has = (a: (c: Card) => boolean, b: (c: Card) => boolean) => pairMatch(cards, a, b);
  const redQ = (c: Card) => isRedRank(c, 'Q');
  const red2 = (c: Card) => isRedRank(c, '2');
  const red8 = (c: Card) => isRedRank(c, '8');
  const red4 = (c: Card) => isRedRank(c, '4');
  const red6 = (c: Card) => isRedRank(c, '6');
  const red10 = (c: Card) => isRedRank(c, '10');
  const black4 = (c: Card) => isBlackRank(c, '4');
  const black6 = (c: Card) => isBlackRank(c, '6');
  const black8 = (c: Card) => isBlackRank(c, '8');
  const black9 = (c: Card) => isBlackRank(c, '9');
  const black10 = (c: Card) => isBlackRank(c, '10');
  const blackJ = (c: Card) => isBlackRank(c, 'J');
  const black5 = (c: Card) => isBlackRank(c, '5');
  const any7 = (c: Card) => c.rank === '7';
  const ding = (c: Card) => isHeart3(c);

  if (has(redQ, any7)) return [6, '天关九'];
  if (has(red2, any7)) return [5, '地关九'];
  if (has(red8, blackJ)) return [4, '灯笼九'];
  if (has(red4, black5)) return [3, '和五九'];
  if (has(black4, black5)) return [2, '板五九'];
  if (has(ding, black6)) return [2, '丁长九'];
  if (has(black10, black9)) return [2, '梅十九'];
  if (has(ding, red6)) return [1, '丁猫九'];
  if (has(black8, blackJ)) return [1, '乌龙九'];
  if (has(red10, black9)) return [1, '苕十九'];
  return [0, '九点']; // 其余 9 点
}

/**
 * 评估两张组牌。排序值层级（越大越强）：
 * 丁皇 1000 > 对子 900+单张值 > 王(奶狗) 800 > 天杠 702 > 地杠 701 >
 * 9点 600+档 > 散牌 100+点数(0..8)
 */
export function evalGroup(cards: [Card, Card]): GroupEval {
  const top = Math.max(singleValue(cards[0]), singleValue(cards[1]));

  // 丁皇：红3 + 大王
  if (pairMatch(cards, isHeart3, isJoker)) {
    return { rank: 1000, name: '丁皇', topSingle: top };
  }

  // 对子（同色同点）：按官方具体名（天牌/地牌/.../梅十/虎头/对子）
  const pv = asPairValue(cards);
  if (pv != null) {
    return { rank: 900 + pv, name: pairName(cards[0]), topSingle: pv };
  }

  // 奶狗：红Q + 9
  if (pairMatch(cards, (c) => isRedRank(c, 'Q'), (c) => c.rank === '9')) {
    return { rank: 800, name: '奶狗', topSingle: top };
  }
  // 天杠：红Q + 8
  if (pairMatch(cards, (c) => isRedRank(c, 'Q'), (c) => c.rank === '8')) {
    return { rank: 702, name: '天杠', topSingle: top };
  }
  // 地杠：红2 + 8
  if (pairMatch(cards, (c) => isRedRank(c, '2'), (c) => c.rank === '8')) {
    return { rank: 701, name: '地杠', topSingle: top };
  }

  // 9 点系
  const nine = nineHand(cards);
  if (nine) {
    return { rank: 600 + nine[0], name: nine[1], topSingle: top };
  }

  // 散牌（点数 0..8）
  const pt = groupPoint(cards);
  return { rank: 100 + pt, name: `${pt}点`, topSingle: top };
}

/**
 * 比较两组牌：返回 >0 表示 a 大，<0 表示 b 大，0 表示相等。
 * 散牌同点比最大单张；其余同 rank 即视为相等。
 */
export function compareGroup(a: GroupEval, b: GroupEval): number {
  if (a.rank !== b.rank) return a.rank - b.rank;
  // 散牌（100..108）同点比最大单张
  if (a.rank >= 100 && a.rank <= 108) {
    return a.topSingle - b.topSingle;
  }
  return 0;
}

// —— 4 张牌：特殊牌型 + 头尾分墩 ——

/** 三花十：红10 + 黑10 + 黑J（+任一张）；三花六：红6 + 黑6 + 大王（+任一张） */
export function specialHand(cards: Card[]): '三花十' | '三花六' | null {
  const hasRed10 = cards.some((c) => isRedRank(c, '10'));
  const hasBlack10 = cards.some((c) => isBlackRank(c, '10'));
  const hasBlackJ = cards.some((c) => isBlackRank(c, 'J'));
  if (hasRed10 && hasBlack10 && hasBlackJ) return '三花十';
  const hasRed6 = cards.some((c) => isRedRank(c, '6'));
  const hasBlack6 = cards.some((c) => isBlackRank(c, '6'));
  const hasJoker = cards.some((c) => isJoker(c));
  if (hasRed6 && hasBlack6 && hasJoker) return '三花六';
  return null;
}

export interface SplitHand {
  head: [Card, Card];
  tail: [Card, Card];
  headEval: GroupEval;
  tailEval: GroupEval;
}

const PARTITIONS: [number, number][][] = [
  [
    [0, 1],
    [2, 3],
  ],
  [
    [0, 2],
    [1, 3],
  ],
  [
    [0, 3],
    [1, 2],
  ],
];

/** 把一种分法整理成 头(大) / 尾(小)，头 ≥ 尾 */
function makeSplit(g1: [Card, Card], g2: [Card, Card]): SplitHand {
  const e1 = evalGroup(g1);
  const e2 = evalGroup(g2);
  if (compareGroup(e1, e2) >= 0) {
    return { head: g1, tail: g2, headEval: e1, tailEval: e2 };
  }
  return { head: g2, tail: g1, headEval: e2, tailEval: e1 };
}

/**
 * 按玩家选定的两张牌（groupIds）作为一墩，另两张为另一墩，整理成头≥尾。
 * 用于本人手动分牌。
 */
export function splitFromChosen(cards: Card[], groupIds: string[]): SplitHand {
  const chosen = cards.filter((c) => groupIds.includes(c.id));
  const rest = cards.filter((c) => !groupIds.includes(c.id));
  if (chosen.length !== 2 || rest.length !== 2) return bestSplit(cards);
  return makeSplit([chosen[0], chosen[1]], [rest[0], rest[1]]);
}

/** 枚举一手 4 张牌的全部 3 种分墩方式 */
export function enumerateSplits(cards: Card[]): SplitHand[] {
  return PARTITIONS.map(([p, q]) => {
    const g1: [Card, Card] = [cards[p[0]], cards[p[1]]];
    const g2: [Card, Card] = [cards[q[0]], cards[q[1]]];
    return makeSplit(g1, g2);
  });
}

/**
 * 自动选择最优分墩：优先尾墩最大（尾大吃皮/芒果且胜负权重高），其次头墩最大。
 */
export function bestSplit(cards: Card[]): SplitHand {
  const splits = enumerateSplits(cards);
  splits.sort((a, b) => {
    const t = compareGroup(b.tailEval, a.tailEval);
    if (t !== 0) return t;
    return compareGroup(b.headEval, a.headEval);
  });
  return splits[0];
}

/**
 * 两名玩家分墩后比牌：返回 >0 表示 a 胜，<0 表示 b 胜，0 表示打和。
 * 头比头、尾比尾：两边都大或一大一平 → 胜；一大一小 → 打和。
 */
export function compareSplit(a: SplitHand, b: SplitHand): number {
  const head = compareGroup(a.headEval, b.headEval);
  const tail = compareGroup(a.tailEval, b.tailEval);
  const aWin = (head > 0 && tail >= 0) || (head >= 0 && tail > 0);
  const bWin = (head < 0 && tail <= 0) || (head <= 0 && tail < 0);
  if (aWin) return 1;
  if (bWin) return -1;
  return 0; // 一大一小，打和
}
