""" 立直麻将和牌点数计算
使用 https://github.com/MahjongRepository/mahjong"""

from mahjong.hand_calculating.hand import HandCalculator
from mahjong.hand_calculating.hand_response import HandResponse
from mahjong.hand_calculating.hand_config import HandConfig, OptionalRules
from mahjong.tile import TilesConverter
from mahjong.constants import (EAST, WEST, SOUTH, NORTH, HAKU, HATSU, CHUN, FIVE_RED_MAN, FIVE_RED_PIN, FIVE_RED_SOU)
from mahjong.hand_calculating.yaku import Yaku

from mahjong.hand_calculating.yaku_list import (
    AkaDora,
    Chankan,
    Chantai,
    Chiitoitsu,
    Chinitsu,
    Chun,
    DaburuOpenRiichi,
    DaburuRiichi,
    Dora,
    Haitei,
    Haku,
    Hatsu,
    Honitsu,
    Honroto,
    Houtei,
    Iipeiko,
    Ippatsu,
    Ittsu,
    Junchan,
    NagashiMangan,
    OpenRiichi,
    Pinfu,
    Renhou,
    Riichi,
    Rinshan,
    Ryanpeikou,
    Sanankou,
    SanKantsu,
    Sanshoku,
    SanshokuDoukou,
    Shosangen,
    Tanyao,
    Toitoi,
    Tsumo,
    YakuhaiEast,
    YakuhaiNorth,
    YakuhaiOfPlace,
    YakuhaiOfRound,
    YakuhaiSouth,
    YakuhaiWest,
)

from mahjong.hand_calculating.yaku_list.yakuman import (
    Chiihou,
    Chinroutou,
    ChuurenPoutou,
    DaburuChuurenPoutou,
    DaburuKokushiMusou,
    Daichisei,
    Daisangen,
    Daisharin,
    DaiSuushii,
    KokushiMusou,
    Paarenchan,
    RenhouYakuman,
    Ryuuiisou,
    Sashikomi,
    Shousuushii,
    Suuankou,
    SuuankouTanki,
    Suukantsu,
    Tenhou,
    Tsuuiisou,
)

from tools.toolbase import *

YAKU_CN_NAME = {
    AkaDora: "红宝牌",
    Tsumo: "自摸",
    Chankan: "抢杠",
    Chantai: "混全带幺九",
    Chiitoitsu: "七对子",
    Chinitsu: "清一色",
    Chun: "中",
    DaburuOpenRiichi: "两立直",
    DaburuRiichi: "双立直",
    Dora: "宝牌",
    Haitei: "海底捞月",
    Haku: "白",
    Hatsu: "发",
    Honitsu: "混一色",
    Honroto: "混老头",
    Houtei: "河底捞鱼",
    Iipeiko: "一杯口",
    Ippatsu: "一发",
    Ittsu: "一气通贯",
    Junchan: "纯全带幺九",
    NagashiMangan: "流局满贯",
    OpenRiichi: "明牌立直",
    Pinfu: "平和",
    Renhou: "人和",
    Riichi: "立直",
    Rinshan: "岭上开花",
    Ryanpeikou: "两杯口",
    Sanankou: "三暗刻",
    SanKantsu: "三杠子",
    Sanshoku: "三色同顺",
    SanshokuDoukou: "三色同刻",
    Shosangen: "小三元",
    Tanyao: "断幺九",
    Toitoi: "对对和",
    YakuhaiEast: "东",
    YakuhaiNorth: "北",
    YakuhaiOfPlace: "自风",
    YakuhaiOfRound: "场风",
    YakuhaiSouth: "南",
    YakuhaiWest: "西",
    # 役满以上
    Chiihou: "地和",
    Chinroutou: "清老头",
    ChuurenPoutou: "九莲宝灯",
    DaburuChuurenPoutou: "纯正九莲宝灯",
    DaburuKokushiMusou: "国士无双十三面",
    Daichisei: "大七星",
    Daisangen: "大三元",
    Daisharin: "大车轮",
    DaiSuushii: "大四喜",
    KokushiMusou: "国士无双",
    Paarenchan: "八连庄",
    RenhouYakuman: "人和役满",
    Ryuuiisou: "绿一色",
    Sashikomi: "放铳",
    Shousuushii: "小四喜",
    Suuankou: "四暗刻",
    SuuankouTanki: "四暗刻单骑",
    Suukantsu: "四杠子",
    Tenhou: "天和",
    Tsuuiisou: "字一色",
}

class Tool_mahjong_agari(ToolBase):
    """ 麻将和牌计算 """

    @property
    def name(self) -> str:
        return "mahjong_agari"

    @property
    def desc(self) -> str:
        return "计算日本麻将和牌点数, 番数, 符数, 以及役种"

    @property
    def function_json(self) -> dict:
        function_definition = {
            "name": "mahjong_agari",
            "description": """计算日本麻将(立直麻将)规则下, 和牌的点数, 番数, 符数, 以及役种。
                输入牌型时, 用m代表万, p代表筒, s代表条, z代表字牌。赤宝牌用0表示, 比如0m表示赤五万。
                对于场风和自风, 用EAST表示东, SOUTH表示南, WEST表示西, NORTH表示北。
                如果某个参数用户没有输入, 则使用默认值""",
            "parameters": {
                "type": "object",
                "properties": {
                    "hand_tiles": {
                        "type": "string",
                        "description": "和牌时的手牌, 包含 win_tile, 例如: 123456m123p123s11z. 手牌需要包含所有副露的牌。如果手牌小于14张,请将win_tile加入到手牌中"
                    },
                    "win_tile": {
                        "type": "string",
                        "description": "和牌时自摸或者荣和的那张牌。例如: 1p。如果用户没有提供, 则假设手牌输入的最后一张牌为 win_tile"
                    },
                    "dora_indicators":{
                        "type": "string",
                        "description": "宝牌指示牌列表, 例: 1m3z。可以为空"
                    },
                    "round_wind":{
                        "type": "string",
                        "description": "场风. 默认为东风 EAST",
                        "enum": ["EAST", "SOUTH", "WEST", "NORTH"]
                    },
                    "player_wind":{
                        "type": "string",
                        "description": "自风. 默认为东风 EAST",
                        "enum": ["EAST", "SOUTH", "WEST", "NORTH"]
                    },
                    "is_trumo":{
                        "type": "boolean",
                        "description": "是否自摸, 如果自摸和牌为True, 荣和他人和牌则为False. 默认为自摸 True"
                    },
                    "is_riichi":{
                        "type": "boolean",
                        "description": "是否已经立直, 如果立直则为True。默认为不立直,为False"
                    }
                },
                "required": ["hand_tiles","win_tile"]
            }
        }
        return function_definition

    def process_toolcall(self, arguments:str, callback_msg:MSG_CALLBACK) -> str:
        """ 计算日麻和牌打点,役种等
        使用方法: 输入手牌，自摸或荣和的牌，以及其他可选信息：是否立直，场风，自风，宝牌。计算和牌役种和点数
        """
        args = json.loads(arguments)
        try:
            # 计算手牌必须包含和牌牌
            hand_tiles = TilesConverter.one_line_string_to_136_array(args["hand_tiles"],True)
            win_tile = TilesConverter.one_line_string_to_136_array(args["win_tile"],True)[0]
            dora_indi = args.get("dora_indicators", None)
            if not dora_indi:
                dora_indi = None
            else:
                dora_indi = TilesConverter.one_line_string_to_136_array(dora_indi, True)

            round_wind = args.get("round_wind", "EAST")
            round_wind = str_to_wind(round_wind)
            player_wind = args.get("player_wind", "EAST")
            player_wind = str_to_wind(player_wind)
            is_trumo = args.get("is_trumo", True)
            is_riichi = args.get("is_riichi", False)
            calculator = HandCalculator()

            note = f"正在计算和牌点数:{args['hand_tiles']}"
            callback_msg(ChatMsg(ContentType.text, note))

            # log_msg = f"计算和牌点数, hand={args['hand_tiles']}, win_tile={args['win_tile']}, dora_indicators={args.get('dora_indicators', None)}"
            # common.logger().info(log_msg)
            config = HandConfig(is_tsumo=is_trumo, is_riichi=is_riichi,
                round_wind=round_wind, player_wind=player_wind,
                options=OptionalRules(has_aka_dora=True, has_open_tanyao=True))
            agari:HandResponse = calculator.estimate_hand_value(hand_tiles, win_tile,
                dora_indicators=dora_indi, config=config)
            if agari.error is not None:
                return agari.error

            print_str = f"和牌{agari.cost['total']}点"
            print_str += f"({agari.han}番{agari.fu}符)"
            yaku_str = ','.join([yaku_cn_name(y) for y in agari.yaku])
            print_str += f"\n役种:[{yaku_str}]"
            print_str += f"\n计算条件: 场风={wind_to_str(round_wind)}, 自风={wind_to_str(player_wind)}"
            if is_trumo:
                print_str += ", 自摸"
            else:
                print_str += ", 荣和"

            return str(print_str)
        except Exception as e:
            return f"计算和牌失败: {str(e)}"



def yaku_cn_name(yaku:Yaku) -> str:
  """返回役的中文"""
  yaku_type = type(yaku)
  if yaku_type not in YAKU_CN_NAME:
    return "未知/不存在"
  ret_str = YAKU_CN_NAME[yaku_type]

  # 如果是dora, 显示数字个数
  if yaku_type in (AkaDora, Dora):
    ret_str += f"{yaku.han_closed}"

  return ret_str


def wind_to_str(wind):
  """ 返回风字中文 """
  if wind == EAST:
    return "东"
  elif wind == SOUTH:
    return "南"
  elif wind == WEST:
    return "西"
  elif wind == NORTH:
    return "北"
  else:
    return "错误"

def str_to_wind(wind_str:str):
  if wind_str == "EAST":
    return EAST
  elif wind_str == "SOUTH":
    return SOUTH
  elif wind_str == "WEST":
    return WEST
  elif wind_str == "NORTH":
    return NORTH
  else:
    return None