import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QAction, 
                             QMessageBox, QVBoxLayout, QWidget,
                             QPushButton, QLabel, QFileDialog, 
                             QDialog, QLineEdit, QFormLayout)
from PyQt5.QtCore import Qt

class ConflictDialog(QDialog):
    def __init__(self, conflicts):
        super().__init__()
        self.setWindowTitle("ID conflict has been detected in your database!")
        self.setGeometry(100, 100, 400, 300)

        self.layout = QFormLayout(self)
        self.inputs = {}
        self.conflicts = conflicts

        self.update_widgets()

        self.fix_button = QPushButton("FIX IT", self)
        self.fix_button.clicked.connect(self.fix_conflicts)
        self.layout.addWidget(self.fix_button)

        self.setLayout(self.layout)

    def update_widgets(self):
        for id_conflict in self.conflicts:
            input_field = QLineEdit(self)
            input_field.setText(id_conflict['value'])
            self.layout.addRow(QLabel(f"{id_conflict['tag']}:"), input_field)
            self.inputs[id_conflict['tag']] = input_field

    def fix_conflicts(self):
        fixed_values = {}
        for tag, input_field in self.inputs.items():
            new_value = input_field.text()
            old_value = self.conflicts[self.find_conflict_index(tag)]['value']
            if new_value != old_value and new_value:  # Ensure the value is not empty
                fixed_values[tag] = new_value
                print(f"{tag} был назначен на {new_value} (предыдущий {old_value})")

        if fixed_values:
            self.parent().handle_fix(fixed_values)  # Notify parent to handle the fixes

        self.close()

    def find_conflict_index(self, tag):
        for index, conflict in enumerate(self.conflicts):
            if conflict['tag'] == tag:
                return index
        return -1

class F1ModManager(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.custom_track_data = None
        self.database_xml = None

    def initUI(self):
        self.setGeometry(100, 100, 800, 600)
        self.setWindowTitle("F1 2014 Track Mod Installer - Beta 1.0")

        central_widget = QWidget(self)
        self.setCentralWidget(central_widget)

        layout = QVBoxLayout(central_widget)

        self.track_label = QLabel("F1 2014 Track Mod Installer", self)
        self.track_label.setStyleSheet("font-size: 32px; font-weight: 700; color: #cbcbcb;")
        layout.addWidget(self.track_label)

        label1 = QLabel("1. Upload the .xml file containing your custom database track mod", self)
        layout.addWidget(label1)

        custom_track_button = QPushButton("Import Custom Track Data", self)
        custom_track_button.clicked.connect(self.import_custom_track_data)
        layout.addWidget(custom_track_button)

        label2 = QLabel("2. Upload the original database.xml file \n3. Save the database file as .xml and import it into the Ego Database Editor", self)
        layout.addWidget(label2)

        database_button = QPushButton("Upload your database.xml", self)
        database_button.clicked.connect(self.upload_database_xml)
        layout.addWidget(database_button)

        save_button = QPushButton("Save database file as .xml", self)
        save_button.clicked.connect(self.save_database_xml)
        layout.addWidget(save_button)

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('File')
        helpMenu = menubar.addMenu('Help')

        newAction = QAction('New', self)
        newAction.triggered.connect(self.new_project)
        fileMenu.addAction(newAction)

        exitAction = QAction('Exit', self)
        exitAction.triggered.connect(self.close)
        fileMenu.addAction(exitAction)

        aboutAction = QAction('About', self)
        aboutAction.triggered.connect(self.show_about)
        helpMenu.addAction(aboutAction)

        self.statusBar().showMessage("Ready")

    def new_project(self):
        self.custom_track_data = None
        self.database_xml = None
        self.statusBar().showMessage("New project started")

    def show_about(self):
        QMessageBox.about(self, "About", "Author - AlonsoBeast\nLink to Our Discord Modding Server: https://discord.gg/KXt7NC3Sue")

    def import_custom_track_data(self):
        options = QFileDialog.Options()
        file_name, _ = QFileDialog.getOpenFileName(self, "Select Custom Track Data File", "", "All Files (*)", options=options)
        if file_name:
            self.custom_track_data = file_name
            self.statusBar().showMessage(f"Imported Custom Track Data: {file_name}")

    def upload_database_xml(self):
        options = QFileDialog.Options()
        file_name, _ = QFileDialog.getOpenFileName(self, "Select Database File", "", "All Files (*)", options=options)
        if file_name:
            self.database_xml = file_name
            self.statusBar().showMessage(f"Uploaded Database File: {file_name}")

    def save_database_xml(self):
        if self.custom_track_data and self.database_xml:
            conflict_list = self.check_for_conflicts()
            if conflict_list:
                conflict_dialog = ConflictDialog(conflict_list)
                conflict_dialog.setParent(self)  # Set the parent correctly
                conflict_dialog.setWindowModality(Qt.ApplicationModal)  # Ensure it is modal
                conflict_dialog.exec_()
            else:
                self.integrate_and_save()

    def handle_fix(self, fixed_values):
        self.apply_fixed_values(fixed_values)

        # After applying fixes, re-check for remaining conflicts
        remaining_conflicts = self.check_for_conflicts()
        if remaining_conflicts:
            self.statusBar().showMessage("There are still unresolved conflicts.")
            conflict_dialog = ConflictDialog(remaining_conflicts)
            conflict_dialog.setParent(self)  # Set the parent correctly
            conflict_dialog.setWindowModality(Qt.ApplicationModal)  # Ensure it is modal
            conflict_dialog.exec_()
        else:
            self.integrate_and_save()  # Proceed if all conflicts are resolved

    def check_for_conflicts(self):
        conflicts = []
        try:
            with open(self.custom_track_data, 'r', encoding='utf-8') as custom_file:
                custom_content = custom_file.read()
            with open(self.database_xml, 'r', encoding='utf-8') as database_file:
                database_content = database_file.read()

            custom_ids = {
                '<track>': self.extract_value(custom_content, 'track', 'id'),
                '<track_car_handling>': self.extract_value(custom_content, 'track_car_handling', 'ID'),
                '<track_fuel_distance>': self.extract_value(custom_content, 'track_fuel_distance', 'ID'),
                '<track_model>': {
                    'calender_glyph': self.extract_value(custom_content, 'track_model', 'calender_glyph'),
                    'calendar_glyph': self.extract_value(custom_content, 'track_model', 'calendar_glyph'),
                    'id': self.extract_value(custom_content, 'track_model', 'id'),
                    'track_id': self.extract_value(custom_content, 'track_model', 'track_id'),
                    'leaderboard_id': self.extract_value(custom_content, 'track_model', 'leaderboard_id'),
                },
                '<track_difficulties>': {
                    'ID': self.extract_value(custom_content, 'track_difficulties', 'ID'),
                    'track': self.extract_value(custom_content, 'track_difficulties', 'track'),
                },
            }

            for tag, id_value in custom_ids.items():
                if isinstance(id_value, dict):
                    for sub_tag, value in id_value.items():
                        if f"<{sub_tag}>" in database_content and value in database_content:
                            conflicts.append({'tag': f"{tag} <{sub_tag}>", 'value': value})
                else:
                    if f"<{tag}>" in database_content and id_value in database_content:
                        conflicts.append({'tag': tag, 'value': id_value})

        except Exception as e:
            self.statusBar().showMessage("Error while checking for conflicts.")
            print(f"Error: {str(e)}")
        
        return conflicts

    def extract_value(self, content, block, tag):
        """Extracts value of `<tag>` from `<block>` in the XML content."""
        start_tag = f'<{block}>'
        end_tag = f'</{block}>'
        start_index = content.find(start_tag)
        end_index = content.find(end_tag, start_index)
        if start_index != -1 and end_index != -1:
            inner_content = content[start_index:end_index]
            start_value = inner_content.find(f'<{tag}>') + len(f'<{tag}>')
            end_value = inner_content.find(f'</{tag}>', start_value)
            if start_value != -1 and end_value != -1:
                return inner_content[start_value:end_value].strip()
        return None

    def apply_fixed_values(self, fixed_values):
        """Applies fixed values to the custom track data in a temporary file."""
        temp_file_name = os.path.join(os.path.dirname(self.custom_track_data), "temp_custom_track_data.xml")

        with open(self.custom_track_data, 'r', encoding='utf-8') as custom_file:
            custom_content = custom_file.read()

        for tag, fixed_value in fixed_values.items():
            original_value = self.extract_value(custom_content, tag, 'id' if 'track' in tag else 'ID')
            # Замена только в том случае, если оно отличается
            if original_value != fixed_value:
                custom_content = custom_content.replace(f"<{tag}>{original_value}</{tag}>", f"<{tag}>{fixed_value}</{tag}>")
        
        with open(temp_file_name, 'w', encoding='utf-8') as temp_file:
            temp_file.write(custom_content)

        self.custom_track_data = temp_file_name  # Обновляем переменную на временный файл

    def integrate_and_save(self):
        if self.custom_track_data and self.database_xml:
            try:
                # Чтение данных из файлов
                with open(self.custom_track_data, 'r', encoding='utf-8') as custom_file:
                    custom_content = custom_file.read()
                with open(self.database_xml, 'r', encoding='utf-8') as database_file:
                    database_content = database_file.read()

                # Разбиваем дополнительный файл на блоки
                custom_blocks = {
                    'track': self.extract_block(custom_content, 'track'),
                    'track_car_handling': self.extract_block(custom_content, 'track_car_handling'),
                    'track_fuel_distance': self.extract_block(custom_content, 'track_fuel_distance'),
                    'track_model': self.extract_block(custom_content, 'track_model'),
                    'track_difficulties': self.extract_block(custom_content, 'track_difficulties')
                }

                # Теги для вставки
                insertion_tags = {
                    'track': ['<track_calendar>', '<track_fuel_distance>'],
                    'track_car_handling': ['<track_difficulties>', '<track_fuel_distance>'],
                    'track_fuel_distance': ['<track_model>', '<calendar_glyph>', '<id>', '<name_string_id>'],
                    'track_model': ['<track_stat_value>', '<track_stat_value>'],
                    'track_difficulties': ['<track_fuel_distance>', '<track_fuel_distance>']
                }

                # Вставка на основе ключевых точек
                for tag, tags in insertion_tags.items():
                    insertion_point = -1
                    for next_tag in tags:
                        insertion_point = database_content.find(next_tag)
                        if insertion_point != -1:  # Если нашли, прекращаем цикл
                            break

                    if insertion_point != -1 and custom_blocks[tag]:
                        # Проверка на наличие track_difficulties
                        if tag == 'track_difficulties':
                            if '<track_difficulties>' not in database_content:
                                continue  # Пропускаем вставку, если тег отсутствует

                        database_content = (
                            database_content[:insertion_point] +
                            custom_blocks[tag] +
                            "\n" +
                            database_content[insertion_point:]
                        )

                file_name, _ = QFileDialog.getSaveFileName(self, "Save Database File", "", "All Files (*)", options=QFileDialog.Options())
                if file_name:
                    with open(file_name, 'w', encoding='utf-8') as output_file:
                        output_file.write(database_content)
                    self.statusBar().showMessage(f"Database saved successfully: {file_name}")
            except Exception as e:
                self.statusBar().showMessage(f"Error during integration: {str(e)}")
        else:
            self.statusBar().showMessage("Please import both data files before saving.")

    @staticmethod
    def extract_block(content, tag):
        """Извлекает блок XML из содержимого для заданного тега."""
        start_tag = f'<{tag}>'
        end_tag = f'</{tag}>'
        start_index = content.find(start_tag)
        end_index = content.find(end_tag, start_index) + len(end_tag)
        if start_index != -1 and end_index != -1:
            return content[start_index:end_index]
        return ''

app = QApplication(sys.argv)
app.setStyleSheet("""
    QMainWindow {
        background-color: #1e1d2b;
        font-family: 'Roboto', sans-serif;
    }
    QLabel {
        color: #cbcbcb;
        font-size: 16px;
    }
    QPushButton {
        background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #ff8a00, stop:1 #e52e71);
        color: #FFFFFF;
        font-size: 16px;
        padding: 10px;
        border-radius: 25px;
    }
    QMenuBar, QStatusBar {
        background-color: #272938;
        color: #FFFFFF;
    }
    QMenuBar::item:selected {
        background-color: #3C3C3C;
    }
    QMenu {
        background-color: #272938;
        color: #FFFFFF;
    }
    QMenu::item:selected {
        background-color: #3C3C3C;
    }
    QMessageBox {
        font-size: 12px;
        font-weight: 200;
        background-color: #1D1D1D;
    }
""")

window = F1ModManager()
window.show()
sys.exit(app.exec_())