import sys, math, fitz  # PyMuPDF
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                             QPushButton, QFileDialog, QLabel, QScrollArea, QComboBox,
                             QInputDialog, QColorDialog, QDialog, QTextEdit, QDialogButtonBox)
from PySide6.QtGui import QPixmap, QImage, QPainter, QPen, QColor, QBrush
from PySide6.QtCore import Qt, QPoint, QRect

class TextInputDialog(QDialog):
    """複数行の入力に対応したカスタムダイアログ"""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("テキストを入力（複数行対応）")
        self.resize(450, 250)
        layout = QVBoxLayout(self)
        self.text_edit = QTextEdit(self)
        self.text_edit.setPlaceholderText("ここに文字を入力（Enterで改行できます）")
        self.text_edit.setStyleSheet("font-size: 14px;")
        layout.addWidget(self.text_edit)
        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        layout.addWidget(buttons)
    def get_text(self): return self.text_edit.toPlainText()

class PDFCanvas(QLabel):
    def __init__(self, main_window):
        super().__init__()
        self.main_window = main_window
        self.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.start_pos = self.end_pos = None
        self.is_drawing = False
        self.base_pixmap = None
    def set_pdf_pixmap(self, pixmap):
        self.base_pixmap = pixmap
        self.setPixmap(pixmap)
        self.resize(pixmap.size())
    def mousePressEvent(self, event):
        if not self.main_window.doc: return
        if event.button() == Qt.LeftButton:
            self.start_pos = self.end_pos = event.position().toPoint()
            self.is_drawing = True
        elif event.button() == Qt.RightButton:
            self.main_window.add_text_at_pos(event.position().toPoint())
    def mouseMoveEvent(self, event):
        if self.is_drawing:
            self.end_pos = event.position().toPoint()
            self.update_drawing_preview()
    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton and self.is_drawing:
            self.end_pos = event.position().toPoint()
            self.is_drawing = False
            mode = self.main_window.current_mode
            if mode == "select": self.main_window.save_crop_jpeg(self.start_pos, self.end_pos)
            else: self.main_window.add_shape_to_pdf(self.start_pos, self.end_pos, mode)
    def update_drawing_preview(self):
        if not self.base_pixmap: return
        preview_pixmap = self.base_pixmap.copy()
        painter = QPainter(preview_pixmap)
        alpha = int(self.main_window.current_opacity * 255)
        q_color = QColor(self.main_window.current_color.red(), self.main_window.current_color.green(), self.main_window.current_color.blue(), alpha)
        pen = QPen(q_color)
        pen.setWidth(self.main_window.current_thickness)
        mode = self.main_window.current_mode
        if mode == "wavy": pen.setStyle(Qt.DotLine)
        painter.setPen(pen)
        if mode == "select":
            painter.setPen(QPen(Qt.blue, 2, Qt.DashLine))
            painter.setBrush(QBrush(QColor(0, 0, 255, 30)))
            painter.drawRect(QRect(self.start_pos, self.end_pos))
        elif mode == "rect":
            painter.setBrush(Qt.NoBrush)
            painter.drawRect(QRect(self.start_pos, self.end_pos).normalized())
        elif mode == "line": painter.drawLine(self.start_pos, self.end_pos)
        elif mode == "wavy": self.draw_wavy_preview(painter, self.start_pos, self.end_pos)
        painter.end()
        self.setPixmap(preview_pixmap)
    def draw_wavy_preview(self, painter, p1, p2):
        dx, dy = p2.x() - p1.x(), p2.y() - p1.y()
        distance = math.hypot(dx, dy)
        if distance == 0: return
        angle = math.atan2(dy, dx)
        wave_length, wave_amplitude = 10, 4
        steps = int(distance / 2)
        prev_pt = p1
        for i in range(steps + 1):
            t = i / steps if steps > 0 else 0
            curr_dist = t * distance
            bx = p1.x() + curr_dist * math.cos(angle)
            by = p1.y() + curr_dist * math.sin(angle)
            wave = wave_amplitude * math.sin((curr_dist / wave_length) * 2 * math.pi)
            wx = bx - wave * math.sin(angle)
            wy = by + wave * math.cos(angle)
            curr_pt = QPoint(int(wx), int(wy))
            if i > 0: painter.drawLine(prev_pt, curr_pt)
            prev_pt = curr_pt

class AdvancedPDFEditor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PySide6 PDF Advanced Editor")
        self.setGeometry(100, 100, 1100, 750)
        self.doc = None
        self.current_page_idx = 0
        self.zoom_factor = 1.5
        self.current_mode = "select"
        self.current_color = QColor(255, 0, 0)
        self.current_thickness = 3
        self.current_opacity = 1.0
        self.init_ui()
    def init_ui(self):
        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        main_layout = QVBoxLayout(main_widget)
        toolbar = QHBoxLayout()
        btn_open = QPushButton("📂 PDFを開く")
        btn_open.clicked.connect(self.open_pdf)
        toolbar.addWidget(btn_open)
        self.btn_prev = QPushButton("◀")
        self.btn_prev.clicked.connect(self.prev_page)
        toolbar.addWidget(self.btn_prev)
        self.page_label = QLabel(" 0 / 0 ")
        toolbar.addWidget(self.page_label)
        self.btn_next = QPushButton("▶")
        self.btn_next.clicked.connect(self.next_page)
        toolbar.addWidget(self.btn_next)
        toolbar.addWidget(QLabel("🔍 倍率:"))
        self.combo_zoom = QComboBox()
        self.combo_zoom.addItems(["25%", "50%", "75%", "100%", "150%", "200%", "300%"])
        self.combo_zoom.setCurrentText("150%")
        self.combo_zoom.currentTextChanged.connect(self.change_zoom)
        toolbar.addWidget(self.combo_zoom)
        toolbar.addWidget(QLabel("🛠️ モード:"))
        self.combo_mode = QComboBox()
        self.combo_mode.addItems(["範囲選択(JPGエクスポート)", "直線引く", "波線引く", "四角枠"])
        self.combo_mode.currentTextChanged.connect(self.change_mode)
        toolbar.addWidget(self.combo_mode)
        toolbar.addWidget(QLabel("太さ:"))
        self.combo_width = QComboBox()
        self.combo_width.addItems(["1", "3", "5", "8", "12"])
        self.combo_width.setCurrentText("3")
        self.combo_width.currentTextChanged.connect(self.change_thickness)
        toolbar.addWidget(self.combo_width)
        toolbar.addWidget(QLabel("透明度:"))
        self.combo_opacity = QComboBox()
        self.combo_opacity.addItems(["1.0 (不透明)", "0.7", "0.5 (蛍光ペン風)", "0.3"])
        self.combo_opacity.setCurrentText("1.0 (不透明)")
        self.combo_opacity.currentTextChanged.connect(self.change_opacity)
        toolbar.addWidget(self.combo_opacity)
        btn_color = QPushButton("🎨 色変更")
        btn_color.clicked.connect(self.choose_color)
        toolbar.addWidget(btn_color)
        self.btn_save = QPushButton("💾 PDF保存")
        self.btn_save.clicked.connect(self.save_pdf)
        toolbar.addWidget(self.btn_save)
        main_layout.addLayout(toolbar)
        self.info_label = QLabel("【操作ヒント】ドラッグで線や範囲選択。画面を「右クリック」すると文字入力ができます。")
        self.info_label.setStyleSheet("color: blue; font-weight: bold;")
        main_layout.addWidget(self.info_label)
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.canvas = PDFCanvas(self)
        self.scroll_area.setWidget(self.canvas)
        main_layout.addWidget(self.scroll_area)
    def change_zoom(self, text):
        self.zoom_factor = int(text.replace("%", "")) / 100.0
        self.render_page()
    def change_mode(self, text):
        m = {"範囲選択(JPGエクスポート)":"select", "直線引く":"line", "波線引く":"wavy", "四角枠":"rect"}
        self.current_mode = m.get(text, "select")
    def change_thickness(self, text): self.current_thickness = int(text)
    def change_opacity(self, text): self.current_opacity = float(text.split(" ")[0])
    def choose_color(self):
        c = QColorDialog.getColor(self.current_color, self, "色を選択")
        if c.isValid(): self.current_color = c
    def open_pdf(self):
        fp, _ = QFileDialog.getOpenFileName(self, "PDFファイルを開く", "", "PDF Files (*.pdf)")
        if fp: self.doc = fitz.open(fp); self.current_page_idx = 0; self.render_page()
    def render_page(self):
        if not self.doc: return
        p = self.doc.load_page(self.current_page_idx)
        m = fitz.Matrix(self.zoom_factor, self.zoom_factor)
        pix = p.get_pixmap(matrix=m)
        qi = QImage(pix.samples, pix.width, pix.height, pix.stride, QImage.Format_RGB888)
        self.canvas.set_pdf_pixmap(QPixmap.fromImage(qi))
        self.page_label.setText(f" {self.current_page_idx + 1} / {len(self.doc)} ")
    def prev_page(self):
        if self.doc and self.current_page_idx > 0: self.current_page_idx -= 1; self.render_page()
    def next_page(self):
        if self.doc and self.current_page_idx < len(self.doc) - 1: self.current_page_idx += 1; self.render_page()
    def screen_to_pdf_rect(self, p1, p2):
        r = QRect(p1, p2).normalized()
        return fitz.Rect(r.left()/self.zoom_factor, r.top()/self.zoom_factor, r.right()/self.zoom_factor, r.bottom()/self.zoom_factor)
    def add_text_at_pos(self, screen_pos):
        d = TextInputDialog(self)
        if d.exec() == QDialog.Accepted:
            t = d.get_text().strip()
            if not t: return
            p = self.doc.load_page(self.current_page_idx)
            px, py = screen_pos.x()/self.zoom_factor, screen_pos.y()/self.zoom_factor
            r = fitz.Rect(px, py - 45, px + 800, py + 400)
            rgb = (self.current_color.red()/255, self.current_color.green()/255, self.current_color.blue()/255)
            annot = p.add_freetext_annot(r, t, fontsize=50, text_color=rgb)
            if annot:
                annot.update()
                self.render_page()
                self.info_label.setText("✓ テキストを追加しました。")

    def add_shape_to_pdf(self, p1, p2, mode):
        p = self.doc.load_page(self.current_page_idx)
        pr = self.screen_to_pdf_rect(p1, p2)
        rgb = (self.current_color.red()/255, self.current_color.green()/255, self.current_color.blue()/255)
        if mode == "line":
            an = p.add_line_annot(pr.p1, pr.p2)
            an.set_border(width=self.current_thickness)
            an.set_colors(stroke=rgb)
            an.set_opacity(self.current_opacity)
            an.update()
        elif mode == "wavy":
            s = p.new_shape()
            dx, dy = pr.p2.x - pr.p1.x, pr.p2.y - pr.p1.y
            dist = math.hypot(dx, dy)
            if dist > 0:
                ang = math.atan2(dy, dx)
                wl, wa = 6, 3
                steps = int(dist / 2)
                pt = pr.p1
                for i in range(steps + 1):
                    t = i / steps if steps > 0 else 0
                    bd = pr.p1.x + (t*dist) * math.cos(ang)
                    by = pr.p1.y + (t*dist) * math.sin(ang)
                    w = wa * math.sin(((t*dist) / wl) * 2 * math.pi)
                    ct = fitz.Point(bd - w * math.sin(ang), by + w * math.cos(ang))
                    if i > 0: s.draw_line(pt, ct)
                    pt = ct
                s.finish(color=rgb, width=self.current_thickness, opacity=self.current_opacity)
                s.commit()
        elif mode == "rect":
            an = p.add_rect_annot(pr)
            an.set_border(width=self.current_thickness)
            an.set_colors(stroke=rgb, fill=None)
            an.set_opacity(self.current_opacity)
            an.update()
        self.render_page()

    def save_crop_jpeg(self, p1, p2):
        if p1 == p2: return
        pr = self.screen_to_pdf_rect(p1, p2)
        if pr.is_empty or pr.width < 5 or pr.height < 5: return
        sp, _ = QFileDialog.getSaveFileName(self, "矩形選択をJPGで保存", "", "JPEG Files (*.jpg)")
        if sp:
            p = self.doc.load_page(self.current_page_idx)
            pix = p.get_pixmap(matrix=fitz.Matrix(0.9, 0.9), clip=pr)
            pix.save(sp)
            self.info_label.setText(f"✓ 保存完了: {sp} (倍率90%)")

    def save_pdf(self):
        if self.doc:
            sp, _ = QFileDialog.getSaveFileName(self, "編集後のPDFを保存", "", "PDF Files (*.pdf)")
            if sp:
                self.doc.save(sp)
                self.info_label.setText(f"✓ PDFを保存しました: {sp}")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = AdvancedPDFEditor()
    window.show()
    sys.exit(app.exec())
