import sys
import os
import argparse # argparseをインポート

# PySide6の必要なモジュールをインポート
from PySide6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QSlider, QFileDialog, QLabel
    )
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput, QMediaFormat
from PySide6.QtMultimediaWidgets import QVideoWidget
from PySide6.QtCore import QUrl, Qt, QSize, Signal
from PySide6.QtGui import QCloseEvent, QDragEnterEvent, QDropEvent # DnDイベント処理に必要

def check_imports(modules):
    """必要なモジュールがインストールされているかを確認する関数"""
    failed = []
    for mod, hint in modules:
        try:
            # モジュールが存在するかを確認
            __import__(mod.split('.')[0], fromlist=["*"])
        except ImportError:
            failed.append((mod, hint))

    if failed:
        print("\n❌ 以下のモジュールがインポートできませんでした：\n")
        for mod, hint in failed:
            print(f"・{mod}\n  → インストール方法: {hint}")
        sys.exit(1)

# チェック対象モジュールとインストールヒント
required_modules = [
    ("configparser", "pip install configparser"),
    ("PySide6.QtWidgets", "pip install PySide6"),
]
check_imports(required_modules)

import configparser


# INIファイル名を設定
INI_FILE = "player_config.ini"

# サポートするメディアファイルのMIMEタイプまたは拡張子を定義
SUPPORTED_MIMES = ["video/mp4", "video/quicktime", "video/x-matroska", "video/x-msvideo"]
SUPPORTED_EXTENSIONS = ["mp4", "mov", "mkv", "avi"]
FILE_DIALOG_FILTER = "Media Files (*.mp4 *.mov *.mkv *.avi);;All Files (*)"

# ----------------------------------------------------------------------
# メインプレイヤーウィンドウ
# ----------------------------------------------------------------------
class QtMediaPlayer(QMainWindow):
    
    def __init__(self, media_path=None, autoplay=False):
        super().__init__()
        self.setWindowTitle("Media Player (Drop Anywhere)")
        
        # 1. プレイヤー要素のセットアップ
        self.player = QMediaPlayer()
        self.audio_output = QAudioOutput()
        self.player.setAudioOutput(self.audio_output)
        
        # プレイヤーからのシグナルを接続
        self.player.durationChanged.connect(self.duration_changed)
        self.player.positionChanged.connect(self.position_changed)
        
        # シーク操作中フラグ
        self.seeking = False
        self.autoplay = autoplay
        
        # --- ウィンドウ全体でドラッグ＆ドロップを有効化 ---
        self.setAcceptDrops(True)

        # 2. UIのセットアップ
        self.setup_ui()
        
        # 3. ウィンドウジオメトリのロード
        self.load_window_geometry() 

        # 4. メディアのロードと再生
        if media_path:
            # 起動時のファイル読み込みでは、autoplay フラグを使用
            self.load_media(media_path, self.autoplay)
        else:
            # ファイルがロードされていない場合は再生ボタンを初期状態に戻す
            self.play_pause_button.setText("▶ Play")
            self.player.setSource(QUrl()) # ソースをクリア

    # --- ドラッグ＆ドロップ関連のメソッド (QMainWindow全体で有効) ---

    def dragEnterEvent(self, event: QDragEnterEvent):
        """ドラッグされたアイテムがウィンドウに入ってきたときの処理"""
        if event.mimeData().hasUrls():
            urls = event.mimeData().urls()
            if urls:
                file_path = urls[0].toLocalFile()
                # 拡張子またはMIMEタイプでメディアファイルか簡易チェック
                if any(file_path.lower().endswith(f".{ext}") for ext in SUPPORTED_EXTENSIONS):
                    event.acceptProposedAction()
                    return
        event.ignore()

    def dropEvent(self, event: QDropEvent):
        """ファイルがウィンドウにドロップされたときの処理"""
        if event.mimeData().hasUrls():
            urls = event.mimeData().urls()
            if urls:
                file_path = urls[0].toLocalFile()
                if file_path and os.path.exists(file_path):
                    print(f"File dropped: {file_path}")
                    # DnDによる読み込みは常に再生を開始
                    self.load_media(file_path, start_playback=True)
            
            event.acceptProposedAction()
        else:
            event.ignore()

    # --- UI設定 ---
            
    def setup_ui(self):
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # 映像表示ウィジェット
        self.video_widget = QVideoWidget()
        # QVideoWidgetはDnDイベントを処理しないため、QMainWindowのDnDが有効になる
        main_layout.addWidget(self.video_widget, stretch=1) 
        self.player.setVideoOutput(self.video_widget)

        # --- シークスライダー ---
        self.position_slider = QSlider(Qt.Orientation.Horizontal)
        self.position_slider.setRange(0, 0)
        self.position_slider.sliderPressed.connect(self.slider_pressed)
        self.position_slider.sliderReleased.connect(self.slider_released)
        main_layout.addWidget(self.position_slider)

        # コントロールパネル
        control_layout = QHBoxLayout()

        open_button = QPushButton("Open File")
        open_button.clicked.connect(self.open_file)
        control_layout.addWidget(open_button)
        
        # 巻き戻しボタンを追加
        self.rewind_button = QPushButton("⏪ Rewind")
        self.rewind_button.clicked.connect(self.rewind_to_start)
        control_layout.addWidget(self.rewind_button)
        
        # 停止ボタンを追加
        self.stop_button = QPushButton("■ Stop")
        self.stop_button.clicked.connect(self.stop_playback)
        control_layout.addWidget(self.stop_button)

        # 再生/一時停止ボタン
        self.play_pause_button = QPushButton("▶ Play")
        self.play_pause_button.clicked.connect(self.toggle_play_pause)
        control_layout.addWidget(self.play_pause_button)

        control_layout.addWidget(QLabel("Speed:"))
        self.speed_slider = QSlider(Qt.Orientation.Horizontal)
        self.speed_slider.setRange(50, 200) # 0.5倍速から2.0倍速
        self.speed_slider.setValue(100)
        self.speed_slider.setMinimumWidth(150)
        self.speed_slider.valueChanged.connect(self.set_speed)
        control_layout.addWidget(self.speed_slider)
        
        main_layout.addLayout(control_layout)

    def load_media(self, file_path, start_playback=True):
        """指定されたファイルをロードし、必要に応じて再生を開始する"""
        if os.path.exists(file_path):
            self.player.setSource(QUrl.fromLocalFile(file_path))
            self.setWindowTitle(f"Media Player - {os.path.basename(file_path)}")
            
            # 再生設定
            if start_playback:
                self.player.play()
                self.play_pause_button.setText("⏸ Pause")
            else:
                self.play_pause_button.setText("▶ Play")
        else:
            print(f"Error: File not found at {file_path}")

    # --- 制御メソッド ---
    
    def toggle_play_pause(self):
        """再生/一時停止の切り替え"""
        if self.player.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self.player.pause()
            self.play_pause_button.setText("▶ Play")
        else:
            self.player.play()
            self.play_pause_button.setText("⏸ Pause")

    def stop_playback(self):
        """再生を停止し、開始位置に戻す"""
        self.player.stop()
        self.play_pause_button.setText("▶ Play")
        
    def rewind_to_start(self):
        """再生位置を最初に巻き戻す"""
        self.player.setPosition(0)
        
    def set_speed(self, value):
        """再生速度の調整 (0.5x - 2.0x)"""
        rate = value / 100.0
        self.player.setPlaybackRate(rate)

    def open_file(self):
        """ファイルダイアログを開き、メディアをロードする"""
        file_dialog = QFileDialog(self)
        file_dialog.setNameFilter(FILE_DIALOG_FILTER)
        if file_dialog.exec():
            file_path = file_dialog.selectedFiles()[0]
            if file_path:
                # ユーザー操作による読み込みは常に再生を開始
                self.load_media(file_path, start_playback=True)

    # --- シーク機能関連のメソッド ---
    
    def slider_pressed(self):
        """スライダーが押されたら、自動更新を一時停止し、シーク中フラグを立てる"""
        self.seeking = True
        
    def slider_released(self):
        """スライダーが離されたら、再生位置を設定し、シーク中フラグを解除する"""
        pos_ms = self.position_slider.value()
        self.player.setPosition(pos_ms)
        self.seeking = False

    def duration_changed(self, duration):
        """メディアの総再生時間 (ミリ秒) が確定したら、スライダーの最大値を設定する"""
        self.position_slider.setRange(0, duration)

    def position_changed(self, position):
        """現在の再生位置 (ミリ秒) が変更されたら、スライダーの現在値を更新する"""
        if not self.seeking:
            self.position_slider.setValue(position)

    # --- INIファイルによるウィンドウジオメトリの保存とロード ---

    def load_window_geometry(self):
        """INIファイルからウィンドウの位置とサイズをロードする"""
        config = configparser.ConfigParser()
        if os.path.exists(INI_FILE):
            config.read(INI_FILE, encoding="utf-8")
            if "Window" in config and "geometry" in config["Window"]:
                geom_str = config["Window"]["geometry"]
                try:
                    x, y, w, h = map(int, geom_str.split(','))
                    self.setGeometry(x, y, w, h)
                    return
                except Exception:
                    pass
        
        screen_size = self.screen().availableGeometry().size()
        default_width = 800
        default_height = 600
        default_x = (screen_size.width() - default_width) // 2
        default_y = (screen_size.height() - default_height) // 2
        self.setGeometry(default_x, default_y, default_width, default_height)


    def save_window_geometry(self):
        """ウィンドウの位置とサイズをINIファイルに保存する"""
        geom = self.geometry()
        geom_str = f"{geom.x()},{geom.y()},{geom.width()},{geom.height()}"

        config = configparser.ConfigParser()
        config["Window"] = {"geometry": geom_str}
        
        try:
            with open(INI_FILE, "w", encoding="utf-8") as f:
                config.write(f)
        except Exception as e:
            print(f"Error saving INI file: {e}", file=sys.stderr)

    def closeEvent(self, event: QCloseEvent):
        """ウィンドウが閉じられる際にジオメトリを保存する"""
        self.player.stop() # 終了時にプレイヤーを停止
        self.save_window_geometry()
        event.accept()

def parse_args():
    """コマンドライン引数を解析する"""
    parser = argparse.ArgumentParser(description="PySide6 Media Player")
    parser.add_argument(
        "infile", 
        nargs='?', 
        default=None, 
        help="起動時に読み込むメディアファイルのパス"
    )
    parser.add_argument(
        "--autoplay", 
        action="store_true", 
        default=False, 
        help="ファイルが指定された場合、自動で再生を開始する"
    )
    parser.add_argument(
        "--ask_open", 
        action="store_true", 
        default=False, 
        help="ファイルが指定されていない場合、ファイル選択ダイアログを表示する"
    )
    return parser.parse_args()


if __name__ == "__main__":
    args = parse_args()
    app = QApplication(sys.argv)
    
    initial_path = args.infile
    
    # 1. infileが指定されているが、ファイルが存在しない場合
    if initial_path and not os.path.exists(initial_path):
        print(f"Warning: Specified file not found: {initial_path}. Proceeding without initial file.")
        initial_path = None
        
    # 2. infileが指定されておらず、--ask_openがTrueの場合
    if not initial_path and args.ask_open:
        file_dialog = QFileDialog()
        file_dialog.setWindowTitle("Select Media File")
        file_dialog.setNameFilter(FILE_DIALOG_FILTER)
        
        if file_dialog.exec():
            initial_path = file_dialog.selectedFiles()[0]
        else:
            # ユーザーがキャンセルし、起動ファイルがない場合は終了
            if not initial_path:
                print("No file selected. Exiting.")
                sys.exit(0)
    
    # initial_pathがNoneの場合でもウィンドウは開く (メディアなしの状態)
    # QtMediaPlayerにautoplayフラグを渡す
    window = QtMediaPlayer(initial_path, args.autoplay)
    window.show()
    
    sys.exit(app.exec())
