import sys
import json
import os
import re
import shutil  # ← 追加：ファイル移動に使用
from datetime import datetime
from PySide6.QtCore import Qt
from PySide6.QtGui import QTextCursor, QColor, QTextCharFormat, QAction
from PySide6.QtWidgets import (QApplication, QHBoxLayout, QMainWindow,
                             QTextEdit, QToolTip, QWidget, QDialog,
                             QVBoxLayout, QTextEdit as QSubTextEdit,
                             QPushButton, QLabel, QLineEdit, QSplitter,
                             QMessageBox, QFileDialog) # ← 追加：フォルダ選択に使用

# 基本の保存先設定（デフォルト）
DEFAULT_DATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
DEFAULT_DB_FILE = os.path.join(DEFAULT_DATA_DIR, "glossary_db.json")

# 設定ファイルのパス（移動先のフォルダパスを記憶するために使用）
CONFIG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json")

# 現在使用中のパスを保持するグローバル変数（最初はデフォルト値）
DATA_DIR = DEFAULT_DATA_DIR
DB_FILE = DEFAULT_DB_FILE

DB_DATA = {}

def get_effective_paths():
    """設定ファイルから現在の有効なパスを取得してグローバル変数を更新する"""
    global DATA_DIR, DB_FILE
    if os.path.exists(CONFIG_FILE):
        try:
            with open(CONFIG_FILE, "r", encoding="utf-8") as f:
                config = json.load(f)
                # 💡 大文字と小文字、どちらで記録されていても安全に取得できるように修正
                saved_dir = config.get("data_dir") or config.get("DATA_DIR")

                if saved_dir and os.path.exists(saved_dir):
                    DATA_DIR = saved_dir
                    DB_FILE = os.path.join(DATA_DIR, "glossary_db.json")
                    return
        except Exception as e:
            print(f"設定読み込みエラー: {e}")
            pass

    # 設定がない、または移動先フォルダが存在しない場合はデフォルトに戻す
    DATA_DIR = DEFAULT_DATA_DIR
    DB_FILE = DEFAULT_DB_FILE

def load_db():
    global DB_DATA, DATA_DIR
    # 読み込み前に最新のパスを確定させる
    get_effective_paths()

    # ✨【追加】確定したDATA_DIRが存在しない場合はここで確実に自動作成する
    try:
        if not os.path.exists(DATA_DIR):
            os.makedirs(DATA_DIR)
    except Exception as e:
        print(f"フォルダ作成エラー: {e}")

    if os.path.exists(DB_FILE):
        try:
            with open(DB_FILE, "r", encoding="utf-8") as f:
                DB_DATA = json.load(f)
            print(f"JSONデータベースを読み込みました: {DB_FILE}")
        except Exception as e:
            print(f"読み込みエラー: {e}")
            DB_DATA = {}
    else:
        # ファイルがない場合は空の辞書で初期化
        DB_DATA = {}

def save_db(heading, text_left, text_right):
    global DATA_DIR, DB_FILE
    try:
        # ✨【追加】保存する直前にも最新の有効なパスを念のため確定させる
        get_effective_paths()

        if not os.path.exists(DATA_DIR):
            os.makedirs(DATA_DIR)

        if not heading:
            heading = "未分類"

        if heading not in DB_DATA:
            DB_DATA[heading] = {"notes": {}}

        DB_DATA[heading]["text_left"] = text_left
        DB_DATA[heading]["text_right"] = text_right
        DB_DATA[heading]["updated_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        with open(DB_FILE, "w", encoding="utf-8") as f:
            json.dump(DB_DATA, f, ensure_ascii=False, indent=4)
        print(f"データをJSONに保存しました: {heading}")
    except Exception as e:
        print(f"保存エラー: {e}")

def move_db_file(parent_window):
    """【新規増設】JSONデータを別のフォルダへ物理移動する関数"""
    global DATA_DIR, DB_FILE

    # 1. 現在のファイルが存在するかチェック
    if not os.path.exists(DB_FILE):
        QMessageBox.warning(parent_window, "エラー", "移動元のデータファイル（JSON）がまだ作成されていません。\n先にデータを保存してください。")
        return

    # 2. 移動先のフォルダを選択させる
    dest_dir = QFileDialog.getExistingDirectory(parent_window, "JSONファイルの移動先フォルダを選択")
    if not dest_dir:
        return  # キャンセル

    # 現在の場所と同じフォルダが選ばれた場合は何もしない
    if os.path.abspath(dest_dir) == os.path.abspath(DATA_DIR):
        QMessageBox.information(parent_window, "お知らせ", "現在と同じフォルダが選択されたため、移動は行われませんでした。")
        return

    # 3. 新しいファイルパスの計算
    new_db_file = os.path.join(dest_dir, "glossary_db.json")

    # 重複チェック
    if os.path.exists(new_db_file):
        reply = QMessageBox.question(
            parent_window, "上書き確認",
            "移動先に同名の 'glossary_db.json' が既に存在します。\n上書きして移動しますか？",
            QMessageBox.Yes | QMessageBox.No
        )
        if reply == QMessageBox.No:
            return

    # 4. 移動処理
    try:
        # 物理移動を実行
        shutil.move(DB_FILE, new_db_file)

        # グローバル変数のパスを更新
        DATA_DIR = dest_dir
        DB_FILE = new_db_file

        # 新しいパスを設定ファイル（config.json）に保存して記憶させる
        with open(CONFIG_FILE, "w", encoding="utf-8") as f:
            json.dump({"data_dir": DATA_DIR}, f, ensure_ascii=False, indent=4)

        QMessageBox.information(parent_window, "移動完了", f"データを新しいフォルダに移動しました！\n\n移動先:\n{DB_FILE}")

    except Exception as e:
        QMessageBox.critical(parent_window, "エラー", f"ファイルの移動中にエラーが発生しました:\n{e}")

def export_to_vertical_html(heading):
    """現在の見出しのデータを縦書きHTMLとして出力する（ホバー連動・ハイライト完全対応版）"""
    if heading not in DB_DATA:
        return False

    data = DB_DATA[heading]
    text_left = data.get("text_left", "")
    text_right = data.get("text_right", "")
    notes = data.get("notes", {})

    # 青空文庫形式 ｜漢字《ルビ》 を HTMLのルビタグに単純置換
    def convert_ruby(text):
        pattern = r"｜([^《]+)《([^》]+)》"
        return re.sub(pattern, r"<ruby>\1<rt>\2</rt></ruby>", text)

    # ✨ [追加] ［赤］タグを HTML の装飾用 span タグに変換する関数
    def convert_red_style(text):
        pattern = r"［赤］(.*?)［／赤］"
        return re.sub(pattern, r'<span class="red-underline">\1</span>', text)

    # 🟢 [新機能追加] ［緑マ］タグを HTML の装飾用 span タグに変換する関数
    def convert_green_marker_style(text):
        pattern = r"［緑マ］(.*?)［／緑マ］"
        # 印刷時にも色が消えないように CSS のスタイルを直接当てます
        return re.sub(pattern, r'<span class="green-marker" style="background-color: #c8f7c5; -webkit-print-color-adjust: exact; color: #000000;">\1</span>', text)

    # 1. まずルビ、赤文字、緑マーカーを変換し、改行を<br>に変換
    # 💡 変換のチェーン（入れ子）に convert_green_marker_style を追加しました
    processed_left = convert_green_marker_style(convert_red_style(convert_ruby(text_left))).replace("\n", "<br>")
    processed_right = convert_green_marker_style(convert_red_style(convert_ruby(text_right))).replace("\n", "<br>")

    # 2. 【大改良】登録されている注記単語を検索し、薄いオレンジのハイライトタグ（span）で包む処理
    # ※短い単語が長い単語の一部を誤って上書きしないよう、単語の長い順に処理します
    sorted_words = sorted(notes.keys(), key=len, reverse=True)

    for word in sorted_words:
        if word in processed_left:
            # マウス連動用の data-word 属性を持たせたspanタグに置換
            highlight_tag = f'<span class="highlight-word" data-word="{word}">{word}</span>'
            processed_left = processed_left.replace(word, highlight_tag)
        if word in processed_right:
            highlight_tag = f'<span class="highlight-word" data-word="{word}">{word}</span>'
            processed_right = processed_right.replace(word, highlight_tag)

    # 3. 注記一覧のHTML（各注記に id を付与してJavaScriptから狙い撃ちできるようにする）
    html_notes = ""
    for word, note in notes.items():
        html_notes += f"""
        <div class="note-item" id="note-{word}" data-word="{word}">
            <b>【{word}】</b><br>{note}
        </div>"""

    if not html_notes:
        html_notes = "<div class='note-item'>注記は登録されていません。</div>"

    # 新しい縦書きHTMLテンプレート（動的JavaScript内蔵モデル）
    html_content = f"""<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{heading} - 縦書き特設ページ</title>
    <style>
        /* 画面全体の基本設定 */
        html, body {{
            margin: 0;
            padding: 0;
            height: 100vh;
            width: 100vw;
            background-color: #fcfaf2;
            color: #333333;
            font-family: "Hiragino Mincho ProN", "Yu Mincho", serif;
            box-sizing: border-box;
            overflow-y: hidden;
            direction: rtl; /* 全体のレイアウト基点を右にする */
        }}

        /* 上部ナビゲーションエリア */
        .nav-bar {{
            position: fixed;
            top: 0;
            right: 0;
            width: 100vw;
            height: 50px;
            background-color: rgba(240, 235, 215, 0.95);
            border-bottom: 1px solid #dcd3b2;
            display: flex;
            justify-content: flex-start;
            align-items: center;
            padding: 0 40px;
            box-sizing: border-box;
            z-index: 1000;
            gap: 15px;
            direction: ltr;
        }}

        .nav-title {{
            font-weight: bold;
            color: #8c6450;
            margin-right: 20px;
        }}

        .nav-btn {{
            background-color: #ffffff;
            border: 1px solid #8c6450;
            color: #8c6450;
            padding: 5px 15px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 0.9rem;
            transition: all 0.2s;
            text-decoration: none;
        }}

        .nav-btn:hover {{
            background-color: #8c6450;
            color: #ffffff;
        }}

        /* 案内メッセージの追加 */
        .nav-info {{
            font-size: 0.85rem;
            color: #666;
            margin-left: auto; /* 右端（ltrなので右）に寄せる */
        }}

        /* 全体を横スクロールさせるための外枠 */
        .outer-scroll-container {{
            height: 100vh;
            width: 100vw;
            overflow-x: auto;
            overflow-y: hidden;
            box-sizing: border-box;
            scroll-behavior: smooth;
        }}

        .wrapper {{
            display: flex;
            flex-direction: row;
            height: 100vh;
            width: max-content;
            box-sizing: border-box;
            padding: 80px 40px 40px 40px;
        }}

        /* 大タイトル（作品名） */
        .main-heading {{
            writing-mode: vertical-rl;
            -webkit-writing-mode: vertical-rl;
            font-size: 1.8rem;
            margin: 0 0 0 50px;
            padding: 0;
            line-height: 1.2;
            height: calc(100vh - 120px);
            align-self: flex-start;
        }}

        /* 3つのボックスを横一列に並べるためのコンテナ */
        .page-container {{
            display: flex;
            flex-direction: row;
            justify-content: flex-start;
            align-items: flex-start;
            height: calc(100vh - 120px);
            width: calc(100vw - 180px);
            gap: 40px;
            box-sizing: border-box;
            scroll-snap-align: start;
        }}

        /* 各セクションの塊 */
        .section-wrap {{
            display: flex;
            flex-direction: row;
            width: calc((100% - 80px) / 3);
            height: 100%;
            box-sizing: border-box;
        }}

        /* 各ボックスのタイトル（見出し） */
        .section-title {{
            writing-mode: vertical-rl;
            -webkit-writing-mode: vertical-rl;
            font-weight: bold;
            color: #8c6450;
            border-right: 4px solid #8c6450;
            padding-right: 8px;
            margin: 0 0 0 12px;
            height: max-content;
            font-size: 1.1rem;
            white-space: nowrap;
        }}

        /* 白いボックス本体 */
        .vertical-book {{
            writing-mode: vertical-rl;
            -webkit-writing-mode: vertical-rl;
            text-orientation: upright;
            flex-grow: 1;
            height: 100%;
            overflow-x: auto;
            overflow-y: hidden;
            border: 1px solid #dcd3b2;
            padding: 30px;
            background-color: #ffffff;
            line-height: 2.4;
            letter-spacing: 0.05em;
            text-align: start;
            box-sizing: border-box;
            border-radius: 4px;
            direction: ltr;
        }}

        /* ★新機能：薄いオレンジ色の背景色ハイライト */
        .highlight-word {{
            background-color: #FFE4B5; /* 元のツールと同じ馴染むオレンジ */
            border-radius: 2px;
            cursor: pointer;
            transition: background-color 0.2s;
        }}
        .green-marker {{
            background-color: #c8f7c5;
            -webkit-print-color-adjust: exact;
            color: #000000;
            display: inline; /* 縦書きでの背景切れを防ぐ保険 */
        }}
        /* マウスが乗ったときには少し濃くして「触れる」ことを伝える */
        .highlight-word:hover, .highlight-word.active-hover {{
            background-color: #FFA500;
        }}

        /* 語句注記一覧専用の背景色調整 */
        .notes-section {{
            background-color: #faf7ee;
            border: 1px solid #e2d9c2;
        }}

        /* 各注記のスタイル */
        .note-item {{
            margin-left: 30px;
            line-height: 1.8;
            display: inline-block;
            padding: 8px;
            border-radius: 4px;
            transition: all 0.3s ease;
            border: 1px solid transparent;
        }}

        /* ★新機能：ホバーされた注記がピカッと目立つための演出クラス */
        .note-item.highlighted-note {{
            background-color: #FFE4B5;
            border: 1px solid #FFA500;
            transform: scale(1.02); /* わずかに大きくして浮き立たせる */
        }}

        /* 他の注記が目立っているとき、関係ない注記を少し薄くして視線を誘導する */
        .notes-section.searching .note-item:not(.highlighted-note) {{
            opacity: 0.3;
        }}

        /* ルビの設定 */
        ruby {{
            display: inline-ruby;
            break-inside: avoid;
        }}
        ruby rt {{
            font-size: 0.55em;
            color: #555555;
            white-space: nowrap;
        }}
        /* ★新機能：HTML出力時の赤文字＋赤下線用の設定 */
        .red-underline {{
            color: #ff0000 !important;
            text-decoration: underline;
            text-decoration-color: #ff0000;
        }}
    </style>
</head>
<body>

    <div class="nav-bar">
        <span class="nav-title">ナビ：</span>
        <a href="#page1" class="nav-btn">１頁（1〜3欄）</a>
        <span class="nav-info">💡 オレンジ色の語句にマウスを乗せると、注記が自動で連動します。</span>
    </div>

    <div class="outer-scroll-container">
        <div class="wrapper">
            <h1 class="main-heading">{heading}</h1>

            <!-- 3. 【右から左へ並ぶ】1画面分のコンテナ -->
            <div class="page-container" id="page1">

                <!-- 【1】　原文 -->
                <div class="section-wrap">
                    <div class="section-title">【原文】</div>
                    <div class="vertical-book">{processed_left}</div>
                </div>

                <!-- 【2】　私見 -->
                <div class="section-wrap">
                    <div class="section-title">【私見】</div>
                    <div class="vertical-book">{processed_right}</div>
                </div>

                <!-- 【3】　注記 -->
                <div class="section-wrap">
                    <div class="section-title">【語句注記一覧】</div>
                    <div class="vertical-book notes-section" id="notesSection">
                        {html_notes}
                    </div>
                </div>

            </div>
        </div>
    </div>

    <!-- 🌟 動的連動を実現するJavaScript 🌟 -->
    <script>
        document.addEventListener('DOMContentLoaded', () => {{
            const words = document.querySelectorAll('.highlight-word');
            const notesSection = document.getElementById('notesSection');

            words.forEach(word => {{
                // 1. マウスが語句の上に乗ったとき
                word.addEventListener('mouseenter', () => {{
                    const targetWord = word.getAttribute('data-word');
                    const targetNote = document.getElementById(`note-${{targetWord}}`);

                    if (targetNote) {{
                        // 注記全体を「探索モード」にして周りを薄くする
                        notesSection.classList.add('searching');
                        // 該当する注記に目立つクラスを付与
                        targetNote.classList.add('highlighted-note');

                        // ★自動スクロール：隠れていても自動的に見える位置へ動かす
                        targetNote.scrollIntoView({{ behavior: 'smooth', block: 'nearest', inline: 'center' }});
                    }}

                    // 同じ単語が複数ある場合、それらすべてを同時にアクティブにする
                    document.querySelectorAll(`.highlight-word[data-word="${{targetWord}}"]`).forEach(el => {{
                        el.classList.add('active-hover');
                    }});
                }});

                // 2. マウスが語句から離れたとき（元の状態に戻す）
                word.addEventListener('mouseleave', () => {{
                    const targetWord = word.getAttribute('data-word');
                    const targetNote = document.getElementById(`note-${{targetWord}}`);

                    notesSection.classList.remove('searching');
                    if (targetNote) {{
                        targetNote.classList.remove('highlighted-note');
                    }}

                    document.querySelectorAll(`.highlight-word[data-word="${{targetWord}}"]`).forEach(el => {{
                        el.classList.remove('active-hover');
                    }});
                }});
            }});
        }});
    </script>

</body>
</html>
"""
    # === 5回目の最下部（ファイルの書き出し部分）を以下に最終差し替え ===
    # 💡 組み立て終わったHTML全体から［赤］タグをHTMLのspanタグに最終置換
    html_content = html_content.replace("［赤］", '<span class="red-underline">')
    html_content = html_content.replace("［／赤］", '</span>')

    try:
        # 保存する直前に、DATA_DIR（dataフォルダ）が存在するか最終確認し、なければ作成
        if not os.path.exists(DATA_DIR):
            os.makedirs(DATA_DIR)

        # ファイル名の作成（見出し名_縦書き.html）
        output_path = os.path.join(DATA_DIR, f"{heading}_縦書き.html")

        # 安全にUTF-8で書き込み
        with open(output_path, "w", encoding="utf-8") as f:
            f.write(html_content)

        print(f"縦書きHTMLを出力しました: {output_path}")
        return output_path # 成功したらメッセージボックスに渡すためにパスを返す

    except Exception as e:
        # 万が一書き込みに失敗した場合はエラーを表示してFalseを返す
        print(f"HTMLファイル書き込みエラー: {e}")
        return False


class NoteInputDialog(QDialog):
    def __init__(self, heading, word, parent=None):
        super().__init__(parent)
        self.setWindowTitle("注記の入力")
        self.resize(350, 200)

        layout = QVBoxLayout(self)
        layout.addWidget(QLabel(f"現在のテキスト: <b>{heading}</b>"))
        layout.addWidget(QLabel(f"対象単語: <b>{word}</b>"))

        self.note_edit = QSubTextEdit()
        self.note_edit.setPlaceholderText("ここに注記を入力。")

        if heading in DB_DATA and word in DB_DATA[heading]["notes"]:
            self.note_edit.setPlainText(DB_DATA[heading]["notes"][word])

        layout.addWidget(self.note_edit)

        self.insert_button = QPushButton("本文へ入力（登録）")
        self.insert_button.clicked.connect(self.accept)
        layout.addWidget(self.insert_button)

    def get_note(self):
        return self.note_edit.toPlainText().strip()


class CustomTextEdit(QTextEdit):
    def __init__(self, note_display_area, parent=None):
        super().__init__(parent)
        self.note_display = note_display_area
        self.setMouseTracking(True)
        self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.customContextMenuRequested.connect(self.show_context_menu)

    def mouseMoveEvent(self, event):
        cursor = self.cursorForPosition(event.position().toPoint())
        pos = cursor.position()
        full_text = self.toPlainText()

        matched_notes = []

        for heading, content in DB_DATA.items():
            if "notes" in content:
                for word, note_text in content["notes"].items():
                    start_idx = 0
                    while True:
                        idx = full_text.find(word, start_idx)
                        if idx == -1:
                            break
                        if idx <= pos <= (idx + len(word)):
                            matched_notes.append(f"【{heading} / 語句: {word}】\n{note_text}")
                            break
                        start_idx = idx + 1

        if matched_notes:
            global_pos = self.mapToGlobal(event.position().toPoint())
            QToolTip.showText(global_pos, "（下部に詳細を表示中）", self)
            self.note_display.setPlainText("\n---\n".join(matched_notes))
        else:
            QToolTip.hideText()

        super().mouseMoveEvent(event)

    def show_context_menu(self, pos):
        menu = self.createStandardContextMenu()
        cursor = self.textCursor()
        selected_text = cursor.selectedText().strip()

        if selected_text:
            menu.addSeparator()

            # --- [既存のメニュー] 注記を追加 ---
            add_note_action = QAction(f"「{selected_text}」に注記を追加。", self)
            main_window = self.window()
            if hasattr(main_window, "open_note_dialog"):
                add_note_action.triggered.connect(lambda: main_window.open_note_dialog(selected_text))
            menu.addAction(add_note_action)

            # --- [既存のメニュー] ルビを振る ---
            add_ruby_action = QAction(f"「{selected_text}」に振り仮名を付加。", self)
            add_ruby_action.triggered.connect(self.open_ruby_dialog_inline)
            menu.addAction(add_ruby_action)

            menu.addSeparator() # さらに見やすくするための区切り線

            # ✨ [新機能] 赤文字＋赤下線を適用するメニュー
            apply_red_action = QAction("「選択範囲」に赤文字＋赤下線を適用", self)
            apply_red_action.triggered.connect(self.apply_red_style)
            menu.addAction(apply_red_action)

            # 🟢 [追加機能] 薄い緑色のラインマーカーを適用するメニュー
            apply_green_marker_action = QAction("「選択範囲」に薄緑のマーカーを適用", self)
            apply_green_marker_action.triggered.connect(self.apply_green_marker_style)
            menu.addAction(apply_green_marker_action)

            # ✨ [新機能] 書式をクリアするメニュー
            clear_style_action = QAction("書式をクリアして元に戻す", self)
            clear_style_action.triggered.connect(self.clear_custom_style)
            menu.addAction(clear_style_action)

        menu.exec(self.mapToGlobal(pos))

    # 💡 装飾を実際に実行するための処理（上記メニューから呼び出されます）
    def apply_red_style(self):
        """選択範囲に赤文字と赤下線を設定する"""
        cursor = self.textCursor()
        if not cursor.hasSelection():
            return

        from PySide6.QtGui import QTextCharFormat, QColor # 未インポートの場合の保険

        fmt = QTextCharFormat()
        fmt.setForeground(QColor("red"))            # 文字色を赤にする
        fmt.setFontUnderline(True)                   # 下線を有効にする
        fmt.setUnderlineColor(QColor("red"))         # 下線の色を赤にする
        fmt.setUnderlineStyle(QTextCharFormat.SingleUnderline) # 通常の下線

        cursor.mergeCharFormat(fmt)
        self.setTextCursor(cursor)

    # 🟢 [追加機能] 薄い緑色のマーカーを実行する処理
    def apply_green_marker_style(self):
        """選択範囲に薄い緑色の背景（マーカー）を設定する"""
        cursor = self.textCursor()
        if not cursor.hasSelection():
            return

        from PySide6.QtGui import QTextCharFormat, QColor

        fmt = QTextCharFormat()
        # 目に優しいパステル調の薄い緑色 (#C8F7C5) を背景色に設定
        fmt.setBackground(QColor("#C8F7C5"))

        cursor.mergeCharFormat(fmt)
        self.setTextCursor(cursor)

    def clear_custom_style(self):
        """選択範囲の書式を初期状態に戻す"""
        cursor = self.textCursor()
        if not cursor.hasSelection():
            return

        from PySide6.QtGui import QTextCharFormat, QColor

        fmt = QTextCharFormat()
        fmt.setForeground(QColor("black"))          # 文字色を黒に戻す
        fmt.setFontUnderline(False)                  # 下線を消す

        cursor.mergeCharFormat(fmt)
        self.setTextCursor(cursor)


    def open_ruby_dialog_inline(self):
        """選択された単語を青空文庫形式のルビタグで包む"""
        cursor = self.textCursor()
        selected_text = cursor.selectedText().strip()

        from PySide6.QtWidgets import QInputDialog

        ruby_text, ok = QInputDialog.getText(
            self, "ルビの入力",
            f"「{selected_text}」の振り仮名を入力。",
            QLineEdit.EchoMode.Normal, ""
        )

        if ok and ruby_text.strip():
            cursor.insertText(f"｜{selected_text}《{ruby_text.strip()}》")

    def highlight_all_registered_words(self):
        fmt = QTextCharFormat()
        fmt.setBackground(QColor("#FFE4B5"))

        for heading, content in DB_DATA.items():
            if "notes" in content:
                for word in content["notes"].keys():
                    cursor = self.document().find(word)
                    while not cursor.isNull():
                        cursor.mergeCharFormat(fmt)
                        cursor = self.document().find(word, cursor)

    def get_tagged_text(self):
        """画面の装飾（赤文字＋下線、薄緑マーカー）を独自タグに変換してプレーンテキストとして取得する"""
        doc = self.document()
        result = ""
        current_block = doc.begin()

        while current_block.isValid():
            iterator = current_block.begin()
            while not iterator.atEnd():
                fragment = iterator.fragment()
                if fragment.isValid():
                    text = fragment.text()
                    fmt = fragment.charFormat()

                    # 赤文字かつ下線があるか判定
                    is_red = fmt.foreground().color().name() == "#ff0000"
                    is_underline = fmt.fontUnderline()

                    # 薄緑マーカーの背景色（#c8f7c5）があるか判定
                    bg_color = fmt.background().color()
                    is_green_marker = bg_color.name() == "#c8f7c5"

                    if is_red and is_underline:
                        result += f"［赤］{text}［／赤］"
                    elif is_green_marker:
                        result += f"［緑マ］{text}［／緑マ］"
                    else:
                        result += text
                iterator += 1

            current_block = current_block.next()
            if current_block.isValid():
                result += "\n"
        return result

    def set_tagged_text(self, text):
        """独自タグ（［赤］［緑マ］）を解析して、画面に各種装飾を再現しながらセットする"""
        self.clear()
        if not text:
            return

        import re
        from PySide6.QtGui import QTextCharFormat, QColor

        # ［赤］...［／赤］ または ［緑マ］...［／緑マ］ で分割するパターン
        pattern = re.compile(r"(［赤］.*?［／赤］|［緑マ］.*?［／緑マ］)")
        parts = pattern.split(text)

        cursor = self.textCursor()

        for part in parts:
            if part.startswith("［赤］") and part.endswith("［／赤］"):
                content = part[3:-4]
                fmt = QTextCharFormat()
                fmt.setForeground(QColor("red"))
                fmt.setFontUnderline(True)
                fmt.setUnderlineColor(QColor("red"))
                fmt.setUnderlineStyle(QTextCharFormat.SingleUnderline)
                cursor.insertText(content, fmt)

            elif part.startswith("［緑マ］") and part.endswith("［／緑マ］"):
                content = part[4:-5] # 「［緑マ］」は4文字、「［／緑マ］」は5文字のため
                fmt = QTextCharFormat()
                fmt.setBackground(QColor("#c8f7c5")) # 薄緑色を背景にセット
                cursor.insertText(content, fmt)

            else:
                # 通常の文字（装飾なし）
                fmt = QTextCharFormat() # デフォルト書式
                cursor.insertText(part, fmt)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("DigitalNote 2026")
        self.resize(950, 650)

        load_db()

        main_layout = QVBoxLayout()

        # --- 上部：管理エリア ---
        top_layout = QHBoxLayout()
        top_layout.addWidget(QLabel("見出し"))
        self.heading_input = QLineEdit()
        self.heading_input.setPlaceholderText("例: 徒然草・序段")
        self.heading_input.setText("徒然草")
        self.heading_input.textChanged.connect(self.load_text_by_heading)
        top_layout.addWidget(self.heading_input)

        # 📄 新規作成ボタン
        new_button = QPushButton("📄 新規データ")
        new_button.setStyleSheet("background-color: #9C27B0; color: white; font-weight: bold; padding: 5px 12px;")
        new_button.clicked.connect(self.trigger_new_data)
        top_layout.addWidget(new_button)

        # 💾 変更を一括保存ボタン
        save_button = QPushButton("💾 一括保存")
        save_button.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 5px 12px;")
        save_button.clicked.connect(self.trigger_save)
        top_layout.addWidget(save_button)

        # 👘 縦書きHTMLを出力ボタン
        export_button = QPushButton("👘 縦書きHTML出力")
        export_button.setStyleSheet("background-color: #008CBA; color: white; font-weight: bold; padding: 5px 12px;")
        export_button.clicked.connect(self.trigger_html_export)
        top_layout.addWidget(export_button)

        # ★ 新設：📖 既存のデータへ切り替えボタン
        switch_button = QPushButton("📖 登録データ一覧")
        switch_button.setStyleSheet("background-color: #03A9F4; color: white; font-weight: bold; padding: 5px 12px;")
        switch_button.clicked.connect(self.trigger_switch_heading)  # 切り替え関数に紐付け
        top_layout.addWidget(switch_button)

        main_layout.addLayout(top_layout)

        # ★ 新設：📁 データの移動ボタン
        move_button = QPushButton("📁 データの移動")
        move_button.setStyleSheet("background-color: #757575; color: white; font-weight: bold; padding: 5px 12px;")
        move_button.clicked.connect(self.trigger_data_move)
        top_layout.addWidget(move_button)

        main_layout.addLayout(top_layout)

        # --- 中央〜下部：立体3ペイン構成 ---
        v_splitter = QSplitter(Qt.Orientation.Vertical)
        h_splitter = QSplitter(Qt.Orientation.Horizontal)

        self.bottom_note_edit = QTextEdit()
        self.bottom_note_edit.setReadOnly(True)
        self.bottom_note_edit.setPlaceholderText("オレンジ色の語句にホバーすると、ここに詳細な注記文が表示されます。")
        self.bottom_note_edit.setStyleSheet("background-color: #F9F9F9; font-size: 12pt;")

        self.text_edit_left = CustomTextEdit(self.bottom_note_edit)
        self.text_edit_left.setPlaceholderText("原文。文字選択⇒右クリックでルビ・注記等を挿入。")
        self.text_edit_left.setStyleSheet("background-color: #EDF2FA; font-size: 16pt;")

        self.text_edit_right = CustomTextEdit(self.bottom_note_edit)
        self.text_edit_right.setPlaceholderText("ここに私見を記載してください。")
        self.text_edit_right.setStyleSheet("background-color: #e1f5df; font-size: 14pt;")

        h_splitter.addWidget(self.text_edit_left)
        h_splitter.addWidget(self.text_edit_right)

        v_splitter.addWidget(h_splitter)
        v_splitter.addWidget(self.bottom_note_edit)

        main_layout.addWidget(v_splitter)

        # 重複部分をすっきり統合し、エラーの原因となっていた不要な呼び出しを削除
        container = QWidget()
        container.setLayout(main_layout)
        self.setCentralWidget(container)

        # 起動時に正しい初期データを読み込む
        self.load_text_by_heading()


    # ★ 新設：登録されているデータ（見出し）を一覧から選んで表示を切り替える関数
    def trigger_switch_heading(self):
        from PySide6.QtWidgets import QInputDialog

        # 1. 念のため現在の画面の入力内容を自動保存
        self.trigger_save()

        # 2. JSON（DB_DATA）に登録されているすべての見出し（作品名）のリストを取得
        headings_list = sorted(list(DB_DATA.keys()))

        if not headings_list:
            QMessageBox.information(self, "お知らせ", "まだデータが一つも登録されていません。\n先に上の「新規データ作成」から作成してください。")
            return

        # 現在表示中の見出しがリストの何番目にあるかを探す（初期選択位置にするため）
        current_heading = self.heading_input.text().strip()
        current_index = headings_list.index(current_heading) if current_heading in headings_list else 0

        # 3. 登録データの一覧をプルダウンで選択させるダイアログを表示
        selected_heading, ok = QInputDialog.getItem(
            self, "データの切り替え",
            "表示するデータ（見出し）を選択してください:",
            headings_list, current_index, False
        )

        # 4. OKが押され、正しく選択されていれば、入力欄を書き換えて画面を切り替える
        if ok and selected_heading:
            # 入力欄の文字が変わることで、自動連動して画面が切り替わります
            self.heading_input.setText(selected_heading)

    # ★ 新設：データ移動のイベントハンドラ
    def trigger_data_move(self):
        self.trigger_save()  # 実行前に安全のため自動保存
        move_db_file(self)   # 上段で定義した移動処理を呼び出し

    def trigger_save(self):
        heading = self.heading_input.text().strip()
        # 💡 toPlainText() から get_tagged_text() に変更
        text_left = self.text_edit_left.get_tagged_text()
        text_right = self.text_edit_right.get_tagged_text()

        global DB_DATA
        if 'DB_DATA' in globals() or 'DB_DATA' in locals() or hasattr(self, 'DB_DATA'):
            DB_DATA[heading] = {
                "text_left": text_left,
                "text_right": text_right,
                "notes": DB_DATA.get(heading, {}).get("notes", {})
            }
        save_db(heading, text_left, text_right)

    # 💡 もしデータを画面のテキストエリアにセットする関数（表示更新処理など）があれば、
    # self.text_edit_left.setText(text_left) 形式の箇所を以下のように書き換えてください。
    # self.text_edit_left.set_tagged_text(text_left)
    # self.text_edit_right.set_tagged_text(text_right)

    def trigger_html_export(self):
        heading = self.heading_input.text().strip()
        self.trigger_save()

        path = export_to_vertical_html(heading)
        if path:
            QMessageBox.information(
                self,
                "出力完了",
                f"縦書きHTMLを出力しました！\n\n【ファイルの場所】\n{path}"
            )
        else:
            QMessageBox.warning(self, "エラー", "データの出力に失敗しました。")

    # 💡【重要修正】関数名を __init__ 側での呼び出し名「load_text_by_heading」に統一しました
    def load_text_by_heading(self):
        """見出しが変更されたときに、データを読み込んで画面にセットする"""
        heading = self.heading_input.text().strip()

        if heading in DB_DATA:
            text_left = DB_DATA[heading].get("text_left", "")
            text_right = DB_DATA[heading].get("text_right", "")

            # ［赤］タグを解析して画面に赤文字＋赤下線の装飾を復元する
            if hasattr(self.text_edit_left, "set_tagged_text"):
                self.text_edit_left.set_tagged_text(text_left)
                self.text_edit_right.set_tagged_text(text_right)
            else:
                self.text_edit_left.setPlainText(text_left)
                self.text_edit_right.setPlainText(text_right)
        else:
            if heading == "章段":
                self.text_edit_left.setPlainText("【原文】")
                self.text_edit_right.setPlainText("【私見】")
            else:
                self.text_edit_left.clear()
                self.text_edit_right.clear()

        # 既存の登録単語ハイライト処理（注記の連動機能など）を呼び出し
        if hasattr(self.text_edit_left, "highlight_all_registered_words"):
            self.text_edit_left.highlight_all_registered_words()
        if hasattr(self.text_edit_right, "highlight_all_registered_words"):
            self.text_edit_right.highlight_all_registered_words()

        self.bottom_note_edit.clear()

    def open_note_dialog(self, word):
        heading = self.heading_input.text().strip()
        if not heading:
            heading = "未分類"

        dialog = NoteInputDialog(heading, word, self)
        if dialog.exec() == QDialog.DialogCode.Accepted:
            note = dialog.get_note()
            if note:
                if heading not in DB_DATA:
                    DB_DATA[heading] = {"notes": {}}

                DB_DATA[heading]["notes"][word] = note

                self.text_edit_left.highlight_all_registered_words()
                self.text_edit_right.highlight_all_registered_words()

    def trigger_new_data(self):
        """現在のデータを安全に保存した上で、新しい作品の入力画面を開く"""
        from PySide6.QtWidgets import QInputDialog

        self.trigger_save()

        new_heading, ok = QInputDialog.getText(
            self, "新規データの作成",
            "新しいテキストの見出し（種類）を入力してください:\n(例: 徒然草、奥の細道など)",
            QLineEdit.EchoMode.Normal, ""
        )

        if ok and new_heading.strip():
            heading = new_heading.strip()

            if heading in DB_DATA:
                QMessageBox.information(self, "確認", f"「{heading}」は既に存在するため、そのデータを読み込みます。")
                self.heading_input.setText(heading)
                return

            DB_DATA[heading] = {
                "text_left": "",
                "text_right": "",
                "notes": {}
            }

            self.heading_input.setText(heading)
            save_db(heading, "", "")
            QMessageBox.information(self, "作成完了", f"新しく「{heading}」の入力画面を用意しました！")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

