import os
import sys
import json

from PySide6.QtCore import QPoint, QSize, Qt, QRect
from PySide6.QtGui import QColor, QLinearGradient, QPainter, QPen, QDragEnterEvent, QDropEvent
from PySide6.QtWidgets import (
    QApplication,
    QFileDialog,
    QLayout,
    QLayoutItem,
    QHBoxLayout,
    QVBoxLayout,
    QLabel,
    QMainWindow,
    QPushButton,
    QScrollArea,
    QWidget,
    QGraphicsDropShadowEffect
)

SAVE_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bookshelf_data.json")

class BookshelfRow(QWidget):
    """
    【本棚の『棚板1段分』を表現する独立したウィジェット】
    背表紙の後ろに一定の余裕（高さ200px）を持たせ、足元に確実な木の棚板を直接描画します。
    """
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFixedHeight(200) # 1段の高さを200pxに完全固定

        # 本を横に並べるためのレイアウト
        self.row_layout = QHBoxLayout(self)
        self.row_layout.setContentsMargins(20, 5, 20, 15)
        self.row_layout.setSpacing(15) # 本と本の隙間
        self.row_layout.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignBottom)

    def paintEvent(self, event):
        """1段ごとに、背後の板と足元の棚板を確実に描画する"""
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)

        # 1. 背後の壁板の描画
        painter.fillRect(self.rect(), QColor("#e0d0b0"))

        # 2. 足元の立体的な棚板（木の厚みと影）の描画
        shelf_top = 185
        gradient = QLinearGradient(0, shelf_top, 0, self.height())
        gradient.setColorAt(0.0, QColor("#b09870")) # 棚板の上のエッジ
        gradient.setColorAt(0.2, QColor("#8c7048")) # 棚板の前面の木目色
        gradient.setColorAt(1.0, QColor("#6e5028")) # 棚板の下の影

        painter.fillRect(QRect(0, shelf_top, self.width(), self.height() - shelf_top), gradient)

        # 棚板の一番上の輪郭線（ハイライト線）
        painter.setPen(QPen(QColor("#cbb593"), 1))
        painter.drawLine(0, shelf_top, self.width(), shelf_top)


class BookSpineWidget(QWidget):
    """立体的な本の背表紙を表現するカスタムウィジェット (2行縦書き・拡張子色分け・ラベル長さ固定版)"""

    def __init__(self, file_path, parent=None):
        super().__init__(parent)
        self.file_path = file_path
        self.title = os.path.basename(file_path)
        self.display_title, self.file_ext = os.path.splitext(self.title)
        self.file_ext = self.file_ext.lower()

        # 背表紙のサイズを縦横完全に固定
        self.setFixedSize(54, 180)

        # 全体を縦に並べるメインレイアウト（上下に少し余白を持たせる）
        main_layout = QHBoxLayout(self)
        main_layout.setContentsMargins(5, 12, 5, 12)
        main_layout.setSpacing(3) # 1行目と2行目のラベルの隙間

        # ラベル背景色（生成り色）の設定
        label_color = QColor(245, 240, 225)
        rgba_str = f"rgba({label_color.red()}, {label_color.green()}, {label_color.blue()}, 235)"

        # タイトル文字列を1列目（最大12文字）と2列目（最大12文字）に分割
        title_chars = list(self.display_title)
        col1_chars = title_chars[:12]
        col2_chars = title_chars[12:24]
        if len(title_chars) > 24:
            if len(col2_chars) > 0:
                col2_chars[-1] = "…"
            else:
                col1_chars[-1] = "…"

        # 日本語の縦書き（右から左）に合わせて、2列目を左、1列目を右に配置
        self.create_column_label(main_layout, col2_chars, rgba_str)
        self.create_column_label(main_layout, col1_chars, rgba_str)

    def create_column_label(self, layout, char_list, rgba_str):
        """文字数に関わらず、常に一定の長さで揃う縦書き列を作成する"""
        # 【修正】空のリスト（2列目が無い本）でも、形が崩れないように空文字をセットしてラベル自体は必ず生成する
        text = "\n".join(char_list) if char_list else ""

        lbl = QLabel(text)
        lbl.setAlignment(Qt.AlignmentFlag.AlignCenter | Qt.AlignmentFlag.AlignTop) # 文字は上詰めで配置

        # 【超重要】ラベル全体の縦の長さを「156px（背表紙180px - 上下余白24px）」に強制ロック！
        # これにより文字が少なくても白（生成り）のラベルシール自体は下まで綺麗に伸びた状態になります。
        lbl.setFixedHeight(156)

        # スタイルシートの設定
        lbl.setStyleSheet(
            f"""
            QLabel {{
                background-color: {rgba_str};
                color: #111111;
                font-weight: bold;
                font-size: 11px;
                line-height: 11px;
                border-radius: 3px;     /* ラベルの角丸 */
                padding: 6px 1px;       /* ラベル内側の余白 */
            }}
            """
        )

        layout.addWidget(lbl)

    def paintEvent(self, event):
        """グラデーションを描画して立体感を出す（拡張子ごとに色を変更）"""
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)

        # 拡張子によるベース色の決定ルール
        if self.file_ext == ".pdf":
            base_color = QColor(140, 45, 65) # ワインレッド
        elif self.file_ext in [".docx", ".doc"]:
            base_color = QColor(45, 85, 140) # ディープブルー
        elif self.file_ext in [".xlsx", ".xls"]:
            base_color = QColor(50, 120, 70)  # オリーブグリーン
        elif self.file_ext == ".txt":
            base_color = QColor(70, 150, 180) # テキストファイルの水色
        else:
            # その他：クラシックブラウン
            hue_offset = abs(hash(self.display_title)) % 20
            base_color = QColor(15 + hue_offset, 130, 140)

        # 立体感を出すための左から右へのグラデーション
        gradient = QLinearGradient(0, 0, self.width(), 0)
        gradient.setColorAt(0.0, base_color.lighter(125))
        gradient.setColorAt(0.15, base_color)
        gradient.setColorAt(0.85, base_color.darker(115))
        gradient.setColorAt(1.0, base_color.darker(145))

        painter.setBrush(gradient)
        painter.setPen(QPen(base_color.darker(160), 1))
        painter.drawRect(0, 0, self.width() - 1, self.height() - 1)

        # 本の上下にある金色の飾り線
        painter.setPen(QPen(QColor(220, 180, 60), 2))
        painter.drawLine(2, 5, self.width() - 3, 5)
        painter.drawLine(2, self.height() - 6, self.width() - 3, self.height() - 6)

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            if os.path.exists(self.file_path):
                os.startfile(self.file_path)


class BookshelfViewer(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("背表紙カスタム本棚ビューア (完全完成版)")
        self.resize(900, 700)

        self.setAcceptDrops(True)

        main_widget = QWidget()
        self.main_layout = QVBoxLayout(main_widget)
        self.setCentralWidget(main_widget)

        top_bar = QHBoxLayout()
        add_btn = QPushButton("ファイルを本棚に追加")
        add_btn.clicked.connect(self.add_files_by_dialog)
        top_bar.addWidget(add_btn)
        top_bar.addStretch()
        self.main_layout.addLayout(top_bar)

        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.scroll_area.setStyleSheet("QScrollArea { border: none; background-color: #e0d0b0; }")
        self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)

        self.shelf_container = QWidget()
        self.shelf_container.setStyleSheet("background-color: #e0d0b0;")
        self.container_layout = QVBoxLayout(self.shelf_container)
        self.container_layout.setContentsMargins(0, 0, 0, 0)
        self.container_layout.setSpacing(0)
        self.container_layout.addStretch()

        self.scroll_area.setWidget(self.shelf_container)
        self.main_layout.addWidget(self.scroll_area)

        self.added_files = []
        self.rows = []

        self.load_bookshelf()

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.rearrange_bookshelf()

    def add_book_to_data(self, file_path):
        if file_path not in self.added_files:
            self.added_files.append(file_path)
            return True
        return False

    def rearrange_bookshelf(self):
        for row in self.rows:
            self.container_layout.removeWidget(row)
            row.deleteLater()
        self.rows.clear()

        max_width = self.scroll_area.viewport().width()
        usable_width = max_width - 40
        if usable_width < 150:
            usable_width = 150

        current_row = BookshelfRow()
        self.container_layout.insertWidget(self.container_layout.count() - 1, current_row)
        self.rows.append(current_row)

        current_width_sum = 0
        book_width = 54
        spacing = 15

        for file_path in self.added_files:
            if current_width_sum + book_width > usable_width:
                if current_width_sum > 0:
                    current_row = BookshelfRow()
                    self.container_layout.insertWidget(self.container_layout.count() - 1, current_row)
                    self.rows.append(current_row)
                    current_width_sum = 0

            book_widget = BookSpineWidget(file_path)
            current_row.row_layout.addWidget(book_widget)
            current_width_sum += book_width + spacing

    def add_files_by_dialog(self):
        files, _ = QFileDialog.getOpenFileNames(self, "ファイルを選択", "", "すべてのファイル (*.*)")
        updated = False
        for file_path in files:
            if self.add_book_to_data(file_path):
                updated = True
        if updated:
            self.save_bookshelf()
            self.rearrange_bookshelf()

    def dragEnterEvent(self, event: QDragEnterEvent):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()

    def dropEvent(self, event: QDropEvent):
        updated = False
        for url in event.mimeData().urls():
            file_path = url.toLocalFile()
            if os.path.exists(file_path):
                if self.add_book_to_data(file_path):
                    updated = True
        if updated:
            self.save_bookshelf()
            self.rearrange_bookshelf()

    def save_bookshelf(self):
        try:
            with open(SAVE_FILE, "w", encoding="utf-8") as f:
                json.dump(self.added_files, f, ensure_ascii=False, indent=4)
        except Exception as e:
            print(f"保存エラー: {e}")

    def load_bookshelf(self):
        """前回保存されたJSONがあれば読み込んで本棚を復元する"""
        if os.path.exists(SAVE_FILE):
            try:
                with open(SAVE_FILE, "r", encoding="utf-8") as f:
                    saved_paths = json.load(f)
                    for file_path in saved_paths:
                        if os.path.exists(file_path):
                            self.added_files.append(file_path)
            except Exception as e:
                print(f"読込エラー: {e}")
        # 最後に本棚を組み立てる
        self.rearrange_bookshelf()


# === 🚀 アプリケーション起動処理 ===
# この部分はインデント（字下げ）を入れず、一番左端から書き始めます。
if __name__ == "__main__":
    app = QApplication.instance()
    if not app:
        app = QApplication(sys.argv)

    viewer = BookshelfViewer()
    viewer.show()

    sys.exit(app.exec())
