import sys
import os
import py7zr
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, QVBoxLayout, QHBoxLayout, QFileDialog, 
                             QLabel, QProgressBar, QLineEdit, QMessageBox, QTabWidget)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import QUrl

class CompressThread(QThread):
    progress = pyqtSignal(int)
    finished = pyqtSignal(str, int, int)

    def __init__(self, files, output_path):
        super().__init__()
        self.files = files
        self.output_path = output_path

    def run(self):
        total_size = sum(os.path.getsize(f) for f in self.files)
        
        filters = [
            {'id': py7zr.FILTER_LZMA2, 'preset': 9 | py7zr.PRESET_EXTREME},
        ]

        with py7zr.SevenZipFile(self.output_path, 'w', filters=filters) as archive:
            for i, file in enumerate(self.files):
                archive.write(file, os.path.basename(file))
                self.progress.emit(int((i + 1) / len(self.files) * 100))

        compressed_size = os.path.getsize(self.output_path)
        self.finished.emit(self.output_path, total_size, compressed_size)

class ExtractThread(QThread):
    progress = pyqtSignal(int)
    finished = pyqtSignal()

    def __init__(self, archive_path, output_dir):
        super().__init__()
        self.archive_path = archive_path
        self.output_dir = output_dir

    def run(self):
        with py7zr.SevenZipFile(self.archive_path, 'r') as archive:
            total_files = len(archive.files)
            for i, _ in enumerate(archive.extractall(path=self.output_dir)):
                self.progress.emit(int((i + 1) / total_files * 100))
        self.finished.emit()

class FileCompressorApp(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Gelişmiş 7zip Sıkıştırma ve Açma Uygulaması')
        self.setGeometry(300, 300, 500, 400)

        layout = QVBoxLayout()

        # Create tab widget
        self.tab_widget = QTabWidget()
        self.compress_tab = QWidget()
        self.extract_tab = QWidget()
        self.tab_widget.addTab(self.compress_tab, "Sıkıştır")
        self.tab_widget.addTab(self.extract_tab, "Aç")

        # Compress tab
        compress_layout = QVBoxLayout()

        self.select_button = QPushButton('Dosyaları Seç')
        self.select_button.clicked.connect(self.selectFiles)
        compress_layout.addWidget(self.select_button)

        self.file_label = QLabel('Seçilen dosya sayısı: 0')
        compress_layout.addWidget(self.file_label)

        self.compress_button = QPushButton('Sıkıştır')
        self.compress_button.clicked.connect(self.compressFiles)
        self.compress_button.setEnabled(False)
        compress_layout.addWidget(self.compress_button)

        self.compress_tab.setLayout(compress_layout)

        # Extract tab
        extract_layout = QVBoxLayout()

        self.select_archive_button = QPushButton('Arşiv Seç')
        self.select_archive_button.clicked.connect(self.selectArchive)
        extract_layout.addWidget(self.select_archive_button)

        self.archive_label = QLabel('Seçilen arşiv: ')
        extract_layout.addWidget(self.archive_label)

        self.extract_button = QPushButton('Aç')
        self.extract_button.clicked.connect(self.extractFiles)
        self.extract_button.setEnabled(False)
        extract_layout.addWidget(self.extract_button)

        self.extract_tab.setLayout(extract_layout)

        layout.addWidget(self.tab_widget)

        self.progress_bar = QProgressBar()
        layout.addWidget(self.progress_bar)

        self.status_label = QLabel('')
        layout.addWidget(self.status_label)

        self.result_label = QLabel('')
        layout.addWidget(self.result_label)

        self.about_button = QPushButton('Hakkında')
        self.about_button.clicked.connect(self.openAboutPage)
        layout.addWidget(self.about_button)

        self.setLayout(layout)

        self.files = []
        self.archive_path = ''

    def selectFiles(self):
        file_dialog = QFileDialog()
        files, _ = file_dialog.getOpenFileNames(self, "Dosyaları Seç", "", "Tüm Dosyalar (*)")
        if files:
            self.files = files
            total_size = sum(os.path.getsize(f) for f in self.files)
            self.file_label.setText(f'Seçilen dosya sayısı: {len(self.files)}, Toplam boyut: {self.format_size(total_size)}')
            self.compress_button.setEnabled(True)

    def selectArchive(self):
        file_dialog = QFileDialog()
        archive_path, _ = file_dialog.getOpenFileName(self, "Arşiv Seç", "", "7zip Dosyaları (*.7z)")
        if archive_path:
            self.archive_path = archive_path
            self.archive_label.setText(f'Seçilen arşiv: {os.path.basename(self.archive_path)}')
            self.extract_button.setEnabled(True)

    def compressFiles(self):
        if not self.files:
            return

        output_path, _ = QFileDialog.getSaveFileName(self, "Sıkıştırılmış Dosyayı Kaydet", "", "7zip Dosyaları (*.7z)")
        if not output_path:
            return

        if not output_path.endswith('.7z'):
            output_path += '.7z'

        self.compress_thread = CompressThread(self.files, output_path)
        self.compress_thread.progress.connect(self.updateProgress)
        self.compress_thread.finished.connect(self.compressionFinished)
        
        self.select_button.setEnabled(False)
        self.compress_button.setEnabled(False)
        self.status_label.setText('Sıkıştırma işlemi devam ediyor... Bu işlem uzun sürebilir.')
        
        self.compress_thread.start()

    def extractFiles(self):
        if not self.archive_path:
            return

        output_dir = QFileDialog.getExistingDirectory(self, "Çıkarılacak Klasörü Seç")
        if not output_dir:
            return

        self.extract_thread = ExtractThread(self.archive_path, output_dir)
        self.extract_thread.progress.connect(self.updateProgress)
        self.extract_thread.finished.connect(self.extractionFinished)
        
        self.select_archive_button.setEnabled(False)
        self.extract_button.setEnabled(False)
        self.status_label.setText('Dosyalar çıkarılıyor... Bu işlem uzun sürebilir.')
        
        self.extract_thread.start()

    def updateProgress(self, value):
        self.progress_bar.setValue(value)

    def compressionFinished(self, output_path, original_size, compressed_size):
        self.select_button.setEnabled(True)
        self.compress_button.setEnabled(True)
        self.status_label.setText('Sıkıştırma işlemi tamamlandı!')
        self.progress_bar.setValue(100)

        compression_ratio = (1 - compressed_size / original_size) * 100
        self.result_label.setText(f'Orijinal boyut: {self.format_size(original_size)}\n'
                                  f'Sıkıştırılmış boyut: {self.format_size(compressed_size)}\n'
                                  f'Sıkıştırma oranı: {compression_ratio:.2f}%')

    def extractionFinished(self):
        self.select_archive_button.setEnabled(True)
        self.extract_button.setEnabled(True)
        self.status_label.setText('Dosyalar başarıyla çıkarıldı!')
        self.progress_bar.setValue(100)

    @staticmethod
    def format_size(size):
        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
            if size < 1024.0:
                return f"{size:.2f} {unit}"
            size /= 1024.0

    def openAboutPage(self):
        QDesktopServices.openUrl(QUrl("https://ettunc.com"))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = FileCompressorApp()
    ex.show()
    sys.exit(app.exec_())
