import gradio as gr
import matplotlib.pyplot as plt
import platform

# 【フォント最適化】ユーザー様の環境に合わせて Noto Serif JP に完全固定
plt.rcParams['font.family'] = 'Noto Serif JP'

def to_vertical(text):
    if not text:
        return ""
    return "\n".join(list(text))

# --- 初期データ ---
people_list = [
    {"name": "若敖", "sub": "（熊儀）", "gen": 1},
    {"name": "伯比", "sub": "〈鬬〉", "gen": 2},
    {"name": "廉",   "sub": "（射師）", "gen": 2},
    {"name": "穀於菟", "sub": "（子文）", "gen": 3},
    {"name": "□",   "sub": "（名不明）", "gen": 3},
    {"name": "班",   "sub": "", "gen": 3},
    {"name": "鬬般", "sub": "（子揚）", "gen": 4},
    {"name": "鬬椒", "sub": "（子越椒）", "gen": 4},
    {"name": "克",   "sub": "", "gen": 4}
]

relations_list = [
    {"father": "若敖", "children": ["伯比", "廉"]},
    {"father": "伯比", "children": ["穀於菟", "□"]},
    {"father": "廉",   "children": ["班"]},
    {"father": "穀於菟", "children": ["鬬般", "鬬椒"]},
    {"father": "班",   "children": ["克"]}
]

def generate_tree_image():
    if not people_list:
        fig, ax = plt.subplots(figsize=(6, 6))
        ax.text(0.5, 0.5, "データがありません", ha='center', va='center', fontsize=14)
        ax.axis('off')
        plt.savefig("current_family_tree.png", bbox_inches='tight')
        plt.close()
        return "current_family_tree.png"

    fig, ax = plt.subplots(figsize=(8, 11))
    canvas_width = 8.0
    canvas_height = 11.0
    ax.set_xlim(0, canvas_width)
    ax.set_ylim(0, canvas_height)
    ax.axis('off')

    # 各世代のY座標（高さ）
    gen_y = {1: 9.0, 2: 6.5, 3: 4.0, 4: 1.5, 5: 0.2}

    person_coords = {}
    connection_points = {}

    # ── 1. 基本的な親の配置 ──
    person_coords["若敖"] = (4.0, gen_y[1])
    person_coords["伯比"] = (5.5, gen_y[2])
    person_coords["廉"]   = (2.5, gen_y[2])

    # ── 2. 動的な子どもの配置ロジック ──
    # 伯比の子どもたち
    rel_barhi = next((r for r in relations_list if r["father"] == "伯比"), {"children": []})
    children_barhi = list(rel_barhi["children"])  # 参照バグを防ぐため複製
    for p in people_list:
        if p["gen"] == 3 and p["name"] not in children_barhi and p["name"] != "班":
            if p["name"] not in ["穀於菟", "□"]:
                children_barhi.append(p["name"])

    num_cb = len(children_barhi)
    span_b = min(3.4, 1.4 * (num_cb - 1)) if num_cb > 1 else 0
    center_xb = 5.3
    for i, c in enumerate(children_barhi):
        cx = (center_xb + span_b/2) - (i * span_b / (num_cb - 1)) if num_cb > 1 else center_xb
        person_coords[c] = (cx, gen_y[3])

    # 廉の子どもたち
    rel_ren = next((r for r in relations_list if r["father"] == "廉"), {"children": ["班"]})
    children_ren = list(rel_ren["children"])
    num_cr = len(children_ren)
    span_r = min(2.0, 1.0 * (num_cr - 1)) if num_cr > 1 else 0
    center_xr = 2.5
    for i, c in enumerate(children_ren):
        cx = (center_xr + span_r/2) - (i * span_r / (num_cr - 1)) if num_cr > 1 else center_xr
        person_coords[c] = (cx, gen_y[3])

    # 穀於菟の子どもたち
    rel_koku = next((r for r in relations_list if r["father"] == "穀於菟"), {"children": ["鬬般", "鬬椒"]})
    children_koku = list(rel_koku["children"])
    num_ck = len(children_koku)
    koku_x = person_coords.get("穀於菟", (5.5, 4.0))[0]
    span_k = min(2.4, 1.2 * (num_ck - 1)) if num_ck > 1 else 0
    for i, c in enumerate(children_koku):
        cx = (koku_x + span_k/2) - (i * span_k / (num_ck - 1)) if num_ck > 1 else koku_x
        person_coords[c] = (cx, gen_y[4])

    # 班の子どもたち
    rel_ban = next((r for r in relations_list if r["father"] == "班"), {"children": ["克"]})
    children_ban = list(rel_ban["children"])
    num_cban = len(children_ban)
    ban_x = person_coords.get("班", (2.5, 4.0))[0]
    span_ban = min(2.0, 1.0 * (num_cban - 1)) if num_cban > 1 else 0
    for i, c in enumerate(children_ban):
        cx = (ban_x + span_ban/2) - (i * span_ban / (num_cban - 1)) if num_cban > 1 else ban_x
        person_coords[c] = (cx, gen_y[4])

    # 完全に配置から漏れた場合のセーフティ
    for p in people_list:
        if p["name"] not in person_coords:
            g = p["gen"] if p["gen"] in gen_y else 4
            person_coords[p["name"]] = (4.0, gen_y[g])

    # ── 3. 文字の描画 ──
    for p in people_list:
        if p["name"] in person_coords:
            x, y = person_coords[p["name"]]
            ax.text(x, y, to_vertical(p["name"]), ha='center', va='top', fontsize=12, linespacing=1.2, zorder=4)
            if p["sub"]:
                ax.text(x - 0.35, y - 0.1, to_vertical(p["sub"]), ha='center', va='top', fontsize=8.5, color='#444444', linespacing=1.1, zorder=4)

    # ── 4. 線引き処理 ──
    if children_barhi and not any(r["father"] == "伯比" for r in relations_list):
         relations_list.append({"father": "伯比", "children": children_barhi})

    for rule in relations_list:
        father = rule["father"]
        if father == "伯比":
            children = children_barhi
        elif father == "廉":
            children = children_ren
        elif father == "穀於菟":
            children = children_koku
        elif father == "班":
            children = children_ban
        else:
            children = rule["children"]

        valid_children = [c for c in children if c in person_coords]
        if not valid_children: continue

        child_xs = [float(person_coords[c][0]) for c in valid_children]
        first_child_name = valid_children[0]
        child_y = float(person_coords[first_child_name][1])

        sibling_line_y = child_y + 0.5
        left_x = min(child_xs)
        right_x = max(child_xs)

        # きょうだい横線
        ax.plot([left_x, right_x], [sibling_line_y, sibling_line_y], color='#222222', lw=1.2)
        # 頭への引き込み縦線
        for cx in child_xs:
            ax.plot([cx, cx], [sibling_line_y, child_y + 0.05], color='#222222', lw=1.2)

        line_center_x = (left_x + right_x) / 2
        connection_points[f"children_of_{father}_in"] = (line_center_x, sibling_line_y)

        if father in person_coords:
            f_x, f_y = person_coords[father][0], person_coords[father][1]
            f_bottom_y = f_y - (len(father) * 0.45 + 0.1)
            connection_points[f"parent_{father}_out"] = (f_x, f_bottom_y)

    # ── 5. クランク結合 ──
    for rule in relations_list:
        father = rule["father"]
        out_key = f"parent_{father}_out"
        in_key = f"children_of_{father}_in"

        if out_key in connection_points and in_key in connection_points:
            out_x, out_y = connection_points[out_key]
            in_x, in_y = connection_points[in_key]

            mid_y = (out_y + in_y) / 2
            ax.plot([out_x, out_x], [out_y, mid_y], color='#222222', lw=1.2)
            ax.plot([out_x, in_x], [mid_y, mid_y], color='#222222', lw=1.2)
            ax.plot([in_x, in_x], [mid_y, in_y], color='#222222', lw=1.2)

    fig.patch.set_facecolor('#fcfaf2')
    output_filename = "current_family_tree.png"
    plt.savefig(output_filename, bbox_inches='tight', dpi=300, facecolor=fig.get_facecolor())
    plt.close()
    return output_filename

# --- インターフェース関数群（Gradio最新仕様） ---
def add_person_and_update(name, gen, sub):
    global people_list
    if name:
        people_list = [p for p in people_list if p["name"] != name]
        people_list.append({"name": name, "sub": sub, "gen": int(gen)})
    choices = get_dropdown_choices()
    return generate_tree_image(), gr.Dropdown(choices=choices)

def add_relation_and_update(father, children_text):
    global relations_list
    if father and children_text:
        children = [c.strip() for c in children_text.split(",") if c.strip()]
        relations_list = [r for r in relations_list if r["father"] != father]
        relations_list.append({"father": father, "children": children})
    return generate_tree_image()

def clear_data():
    global people_list, relations_list
    people_list = []
    relations_list = []
    return generate_tree_image(), gr.Dropdown(choices=[])

def get_dropdown_choices():
    return [p["name"] for p in people_list]

# --- UIの組み立て ---
with gr.Blocks() as demo:
    gr.Markdown("# 🏯 東洋伝統書式 家系図アプリケーション")

    with gr.Row():
        with gr.Column(scale=1):
            with gr.Group():
                gr.Markdown("### 👤 1. 人物の新規登録")
                name_input = gr.Textbox(label="名前（名不明は □ など）", value="子良")
                gen_input = gr.Number(label="世代（段目：1〜10）", value=3, precision=0)
                sub_input = gr.Textbox(label="添え字（字や官職など）", value="")
                btn_add_person = gr.Button("人物をリストに追加", variant="primary")

            with gr.Group():
                gr.Markdown("### 🔗 2. 親子関係（タグ）の登録")
                father_select = gr.Dropdown(label="親（父親）を選択", choices=get_dropdown_choices(), value="伯比")
                children_input = gr.Textbox(label="子供たちの名前（カンマ「,」区切り）", value="穀於菟, □, 子良")
                btn_add_relation = gr.Button("親子関係（タグ）を結ぶ", variant="secondary")

            btn_clear = gr.Button("🗑️ データを全消去してリセット", variant="stop")

        with gr.Column(scale=2):
            gr.Markdown("### 🖼️ 家系図プレビュー")
            output_image = gr.Image(value=generate_tree_image(), type="filepath", label="家系図画像")

    btn_add_person.click(fn=add_person_and_update, inputs=[name_input, gen_input, sub_input], outputs=[output_image, father_select])
    btn_add_relation.click(fn=add_relation_and_update, inputs=[father_select, children_input], outputs=output_image)
    btn_clear.click(fn=clear_data, outputs=[output_image, father_select])

if __name__ == "__main__":
    demo.launch(inbrowser=True, theme="soft")
