import sys
import os
import re
import time
from datetime import datetime
from utils.utility import Utilities
from utils.image_handler import ImageProcessor, ExifHandler

from ui.main_window import Ui_MainWindow

from PySide6 import QtWidgets
from PySide6.QtWidgets import (
    QMessageBox,
    QApplication,
    QMainWindow,
    QWidget,
    QVBoxLayout,
    QLabel,
    QLineEdit,
    QPushButton,
    QCheckBox,
    QFileDialog,
    QHBoxLayout,
    QSpinBox,
)

class Optima35QT6(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(Optima35QT6, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.define_settings()
        self.setWindowTitle(f"{self.name} v{self.version}")
        self.define_gui_interaction()

    def define_gui_interaction(self):
        self.ui.input_folder_button.clicked.connect(self.browse_input_folder)
        self.ui.output_folder_button.clicked.connect(self.browse_output_folder)
        self.ui.start_button.clicked.connect(self.process)

    def define_settings(self):
        self.name = "OPTIMA-35"
        self.version = "0.3.0"
        self.utilities = Utilities()
        self.image_processor = ImageProcessor()
        self.exif_handler = ExifHandler()
        self.settings = {
            "input_folder": None,
            "output_folder": None,
            "file_format": None,
            "resize_percentage": False,
            "contrast_percentage": False,
            "brightness_percentage": False,
            "new_file_names": False,
            "invert_image_order": False,
            "copy_exif": False,
            "own_exif": False,
            "watermark": False,
            "grayscale": False,
            "jpg_quality": None,
            "png_compression": None
        }
        self.exif_data = None

    def browse_input_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "Select Input Folder")
        if folder:
            self.ui.input_path.setText(folder)

    def browse_output_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "Select Output Folder")
        if folder:
            self.ui.output_path.setText(folder)

    def process(self):
        self.check_options()
        if os.path.exists(self.settings["input_folder"]) and os.path.exists(self.settings["output_folder"]):
            print(self.settings)
        else:
            print(self.settings)
            QMessageBox.warning(self, "Warning", "Input and/or output folder invalid...")
            return

        input_folder = self.settings["input_folder"]
        output_folder = self.settings["output_folder"]

        image_files = [
            f for f in os.listdir(input_folder) if f.lower().endswith((".png", ".jpg", ".jpeg", ".webp"))
        ]

        i = 1
        for image_file in image_files:
            input_path = os.path.join(input_folder, image_file)

            if self.settings["new_file_names"] != False:
                image_name = self.name_images(self.settings["new_file_names"], i, len(image_files), self.settings["invert_image_order"])
            else:
                image_name = os.path.splitext(image_file)[0]

            output_path = os.path.join(output_folder, image_name)

            with self.image_processor.open_image(input_path) as img:
                processed_img = img

                if self.settings["resize_percentage"] != False:
                    processed_img = self.image_processor.resize_image(
                        image = processed_img, percent = self.settings["resize_percentage"]
                    )
                if self.settings["watermark"] != False:
                    processed_img = self.image_processor.add_watermark(processed_img, self.settings["watermark"])

                if self.settings["grayscale"] != False: # There is a problem, if we first to grayscale and then watermark it braeks
                    processed_img = self.image_processor.grayscale(processed_img)
                if self.settings["brightness_percentage"] != False: # Does the order of brightness and contrast matter?
                    processed_img = self.image_processor.change_brightness(processed_img, self.settings["brightness_percentage"])
                if self.settings["contrast_percentage"] != False: # Does the order of brightness and contrast matter?
                    processed_img = self.image_processor.change_contrast(processed_img, self.settings["contrast_percentage"])

                if self.settings["copy_exif"] != False:
                    # When copying exif from original, make sure to change Piexel X & Y Dimension to fit new size
                    try:
                        og_exif = self.exif_handler.get_exif_info(img)
                        og_exif["Exif"][40962], og_exif["Exif"][40963] = self.image_processor.get_image_size(processed_img)
                        exif_data = og_exif
                    except Exception:
                        # If an error happends it is because the picture does not have exif data
                        print("Copying EXIF data selected, but no EXIF data is available in the original image file.")
                        exif_data = None
                elif self.settings["copy_exif"] == False:
                    exif_data = None

                self.image_processor.save_image(
                    image = processed_img,
                    path = output_path,
                    exif_data = exif_data,
                    file_type = self.settings["file_format"],
                    jpg_quality = self.settings["jpg_quality"],
                    png_compressing = self.settings["png_compression"],
                    optimize = False
                )
            self.handle_qprogressbar(i, len(image_files))
            i += 1
        QMessageBox.information(self, "Information", "Finished")
        self.ui.progressBar.setValue(0)

    def handle_qprogressbar(self, current, total):
        progress = int((100 / total) * current)
        self.ui.progressBar.setValue(progress)

    def name_images(self, base_name, current_image, total_images, invert):
        """"Returns name, combination of base_name and ending number."""
        total_digits = len(str(total_images))
        if invert:
            ending_number = total_images - (current_image - 1)
        else:
            ending_number = current_image
        ending = f"{ending_number:0{total_digits}}"
        return f"{base_name}_{ending}"

    def check_options(self):
        try:
            self.settings["input_folder"] = self.ui.input_path.text()
            self.settings["output_folder"] = self.ui.output_path.text()
            self.settings["file_format"] = self.ui.image_type.currentText()
            self.settings["jpg_quality"] = int(self.ui.jpg_quality_spinBox.text())
            self.settings["png_compression"] = int(self.ui.png_quality_spinBox.text())
            self.settings["invert_image_order"] = self.ui.revert_checkbox.isChecked()
            self.settings["grayscale"] = self.ui.grayscale_checkBox.isChecked()
            self.settings["copy_exif"] = self.ui.copy_exif_checkBox.isChecked()
            self.settings["own_exif"] = self.ui.exif_checkbox.isChecked()

            if self.ui.resize_checkbox.isChecked():
                self.settings["resize_percentage"] = int(self.ui.resize_spinBox.text())

            if self.ui.brightness_checkbox.isChecked():
                self.settings["brightness_percentage"] = int(self.ui.brightness_spinBox.text())

            if self.ui.contrast_checkbox.isChecked():
                self.settings["contrast_percentage"] = int(self.ui.contrast_spinBox.text())

            if self.ui.rename_checkbox.isChecked() and self.ui.filename.text() != "":
                self.settings["new_file_names"] = self.ui.filename.text()

            if self.ui.watermark_checkbox.isChecked() and self.ui.watermark_lineEdit.text() != "":
                self.settings["watermark"] = self.ui.watermark_lineEdit.text()

        except Exception as e:
            print(f"Whoops: {e}")

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    window = Optima35QT6()
    window.show()
    app.exec()