import os
import tkinter as tk
from tkinter import filedialog, messagebox

# ドラッグ＆ドロップ用のライブラリをインポート
from tkinterdnd2 import DND_FILES, TkinterDnD


class TextCombinerApp:

    def __init__(self, root):
        self.root = root
        self.root.title("テキストファイル結合ツール (pdfas風 - D&D対応)")
        self.root.geometry("600x450")  # D&Dの案内を入れるため少し縦を広げました

        # ファイルパスを保存するリスト
        self.file_paths = []

        # 画面のレイアウト作成
        self.create_widgets()

        # ドラッグ＆ドロップの設定
        self.setup_dnd()

    def create_widgets(self):
        # 上部：操作案内ラベル
        info_label = tk.Label(
            self.root,
            text="下にファイルをドラッグ＆ドロップするか、「ファイルを追加」ボタンから選択してください",
            font=("Arial", 9),
            fg="#555555",
            pady=5,
        )
        info_label.pack(side=tk.TOP, fill=tk.X)

        # メインフレーム
        main_frame = tk.Frame(self.root, padx=10, pady=5)
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 左側：ファイルリストボックス
        self.listbox = tk.Listbox(
            main_frame, selectmode=tk.SINGLE, font=("Arial", 10)
        )
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))

        # 右側：操作ボタンのフレーム
        btn_frame = tk.Frame(main_frame)
        btn_frame.pack(side=tk.RIGHT, fill=tk.Y)

        # 操作ボタン一覧
        tk.Button(
            btn_frame,
            text="ファイルを追加",
            command=self.add_files,
            width=15,
            bg="#e1e1e1",
        ).pack(pady=5)
        tk.Button(
            btn_frame,
            text="上へ移動 (▲)",
            command=self.move_up,
            width=15,
        ).pack(pady=5)
        tk.Button(
            btn_frame,
            text="下へ移動 (▼)",
            command=self.move_down,
            width=15,
        ).pack(pady=5)
        tk.Button(
            btn_frame,
            text="選択削除",
            command=self.remove_file,
            width=15,
        ).pack(pady=5)
        tk.Button(
            btn_frame, text="リストクリア", command=self.clear_list, width=15
        ).pack(pady=5)

        # 下部：結合ボタン
        bottom_frame = tk.Frame(self.root, pady=15)
        bottom_frame.pack(fill=tk.X, side=tk.BOTTOM)

        combine_btn = tk.Button(
            bottom_frame,
            text="並び順でファイルを結合する",
            command=self.combine_files,
            font=("Arial", 11, "bold"),
            bg="#4CAF50",
            fg="white",
            padx=20,
            pady=5,
        )
        combine_btn.pack()

    def setup_dnd(self):
        """リストボックスとアプリ全体にD&Dを登録する"""
        # リストボックスにファイルをドロップできるようにする
        self.listbox.drop_target_register(DND_FILES)
        self.listbox.dnd_bind("<<Drop>>", self.handle_drop)

    def handle_drop(self, event):
        """ドロップされたファイルパスを解析してリストに追加する"""
        # tkinterdnd2特有のパスの区切り（スペースや中括弧）を正しくパースする
        raw_data = event.data

        # Windowsなどで、スペースを含むパスが中括弧 `{ }` で囲まれる対策
        files = []
        if "{" in raw_data:
            # 中括弧で区切られたパスを抽出
            import re

            files = re.findall(r"\{(.*?)\}", raw_data)
            # 中括弧に含まれなかったファイルも取得
            remaining = re.sub(r"\{.*?\}", "", raw_data).split()
            files.extend([f for f in remaining if f])
        else:
            # スペース区切りの単純なリスト（スペースを含まないパスの場合）
            files = raw_data.split()

        # リストに追加
        if files:
            for f in files:
                # パスの前後の余分なクォーテーションなどを削除
                cleaned_path = f.strip().strip('"').strip("'")
                # ファイルが存在し、まだ登録されていなければ追加
                if os.path.isfile(cleaned_path) and (
                    cleaned_path not in self.file_paths
                ):
                    self.file_paths.append(cleaned_path)
            self.update_listbox()

    def update_listbox(self):
        """画面上のリストボックスの表示を最新にする"""
        self.listbox.delete(0, tk.END)
        for path in self.file_paths:
            self.listbox.insert(tk.END, os.path.basename(path))

    def add_files(self):
        """ファイル選択ダイアログを開いて追加（複数選択可）"""
        files = filedialog.askopenfilenames(
            title="テキストファイルを選択",
            filetypes=[("Text files", "*.txt"), ("All files", "*.*")],
        )
        if files:
            for f in files:
                if f not in self.file_paths:
                    self.file_paths.append(f)
            self.update_listbox()

    def move_up(self):
        """選択したファイルを1つ上に移動"""
        try:
            selected = self.listbox.curselection()
            if not selected:
                return
            selected_index = selected[0]
            if selected_index == 0:
                return

            self.file_paths[selected_index], self.file_paths[selected_index - 1] = (
                self.file_paths[selected_index - 1],
                self.file_paths[selected_index],
            )
            self.update_listbox()
            self.listbox.select_set(selected_index - 1)
        except Exception:
            pass

    def move_down(self):
        """選択したファイルを1つ下に移動"""
        try:
            selected = self.listbox.curselection()
            if not selected:
                return
            selected_index = selected[0]
            if selected_index == len(self.file_paths) - 1:
                return

            self.file_paths[selected_index], self.file_paths[selected_index + 1] = (
                self.file_paths[selected_index + 1],
                self.file_paths[selected_index],
            )
            self.update_listbox()
            self.listbox.select_set(selected_index + 1)
        except Exception:
            pass

    def remove_file(self):
        """選択したファイルをリストから削除"""
        try:
            selected = self.listbox.curselection()
            if not selected:
                return
            selected_index = selected[0]
            del self.file_paths[selected_index]
            self.update_listbox()
        except Exception:
            pass

    def clear_list(self):
        """リストをすべて空にする"""
        self.file_paths.clear()
        self.update_listbox()

    def combine_files(self):
        """並び順通りにファイルを結合して保存"""
        if not self.file_paths:
            messagebox.showwarning(
                "警告", "結合するファイルが追加されていません。"
            )
            return

        save_path = filedialog.asksaveasfilename(
            title="名前を付けて結合ファイルを保存",
            defaultextension=".txt",
            filetypes=[("Text files", "*.txt"), ("All files", "*.*")],
        )

        if not save_path:
            return

        try:
            with open(save_path, "w", encoding="utf-8") as outfile:
                for fname in self.file_paths:
                    with open(fname, "r", encoding="utf-8") as infile:
                        outfile.write(infile.read())
                        outfile.write("\n")  # 末尾の改行対策

            messagebox.showinfo("成功", "ファイルの結合が完了しました！")
        except Exception as e:
            messagebox.showerror(
                "エラー", f"ファイルの書き込み中にエラーが発生しました:\n{e}"
            )


if __name__ == "__main__":
    # TkinterDnD.Tk() を使うことで、D&Dが有効なベースウィンドウを作成します
    root = TkinterDnD.Tk()
    app = TextCombinerApp(root)
    root.mainloop()
