import os
import tempfile
import xml.etree.ElementTree as ET
from pathlib import Path

from PyQt5.QtCore import QSize, Qt
from PyQt5.QtGui import QColor
from qgis.PyQt import QtWidgets
from qgis.PyQt.QtWidgets import QGridLayout
from qgis.core import QgsSymbol, QgsSvgMarkerSymbolLayer, QgsWkbTypes

from .custom_color_button import CustomColorButton
from .custom_symbol_button import CustomSymbolButton
from .path_utils import create_existing_icon_path
from .table_row import TableRow
from .third_party_libraries.pyqt_svg_button import SvgButton

BTN_SIZE = QSize(35, 35)
TEMP_ICONS = []
DEFAULT_ICON_SIZE = 2


class ChooserWidget(QtWidgets.QWidget):
    def __init__(self, parent=None, table_row=None, is_color: bool = None):
        super().__init__(None)

        self.temp_icons = []
        self.current_icon_path = None  # Store the current icon path

        self.btn1 = SvgButton()
        self.btn2 = SvgButton()
        self.btn3 = SvgButton()
        self.btn4 = SvgButton()

        self.setWindowFlags(
            (self.windowFlags() | Qt.CustomizeWindowHint) & ~Qt.WindowMaximizeButtonHint & ~Qt.WindowMinimizeButtonHint)
        self.layer = table_row.vectorlayer
        self.table_row = table_row

        # Store the current icon path if it exists
        if not self.layer.is_default_symbol:
            current_symbol = self.layer.qgs_layer.renderer().symbol()
            if current_symbol is not None:
                symbol_layer = current_symbol.symbolLayer(0)
                if isinstance(symbol_layer, QgsSvgMarkerSymbolLayer):
                    try:
                        self.current_icon_path = create_existing_icon_path(symbol_layer.path())
                    except:
                        self.current_icon_path = None

        self.layout = QGridLayout()
        self.setFixedSize(QSize(195, 55))

        if is_color:
            self.setWindowTitle("Colors: " + self.layer.name)
            self.set_color_for_buttons()
        else:
            self.setWindowTitle("Icons: " + self.layer.name)
            self.set_icon_for_buttons()

        self.setLayout(self.layout)

        self.move(parent.mapFromGlobal(parent.mapToGlobal(parent.cursor().pos())).x() - self.width() // 2, 
                  parent.mapFromGlobal(parent.mapToGlobal(parent.cursor().pos())).y() - self.height() // 2)

        self.show()

        self.setFocus()

    # sets the colors for the color buttons
    def set_color_for_buttons(self):
        btns = [self.btn1, self.btn2, self.btn3, self.btn4]
        for i, btn in enumerate(btns):
            if i == 0:
                btn.setToolTip("Default")
            else:
                btn.setToolTip("Suggested Color")
            self.set_color_for_button(btn, i)

    # sets a color for a color button
    def set_color_for_button(self, btn: SvgButton, pos: int):
        self.layout.addWidget(btn, 0, pos)

        btn.setFixedSize(BTN_SIZE)
        btn.setBackground(self.layer.suggested_colors[pos].name())
        btn.setBorderRadius(10)

        if self.layer.suggested_colors[pos] == self.layer.suggested_symbol.color():
            btn.setBorderThickness(3)

        btn.clicked.connect(self.func_for_changing_layer_style_color(pos))
        btn.clicked.connect(self.close)

    def func_for_changing_layer_style_color(self, j: int):
        return lambda: change_layer_style(table_row=self.table_row, color=self.layer.suggested_colors[j],
                                          symbol_button=self.table_row.icon_field,
                                          color_button=self.table_row.color_field)

    # sets the icons for the icon buttons
    def set_icon_for_buttons(self):
        self.set_icon_for_default_symbol(self.btn1)
        self.btn1.setToolTip("Current Icon")

        btns = [self.btn2, self.btn3, self.btn4]
        for i, btn in enumerate(btns):
            btn.setToolTip(Path(self.layer.suggested_icons[i]).stem)
            self.set_icon_for_button(btn, i)

    def set_icon_for_default_symbol(self, btn: SvgButton):
        # Use the current layer's symbol instead of default symbol
        current_symbol = self.layer.qgs_layer.renderer().symbol()
        
        # If we have a stored current icon path, use it
        if self.current_icon_path and os.path.exists(self.current_icon_path):
            temp_icon = create_temp_svg(self.current_icon_path, self.layer.suggested_symbol.color().name(), "1", "black", "1", "2")
            is_default = False
        else:
            # Fallback to default symbol
            temp_icon = create_temp_svg_for_default_symbol(QgsSymbol.defaultSymbol(self.layer.qgs_layer.geometryType()),
                                                       self.layer.suggested_symbol.color())
            is_default = True

        self.icon_btn_style(btn, temp_icon, 0)

        if self.layer.is_default_symbol:
            btn.setBorderThickness(3)

        btn.clicked.connect(
            lambda: change_layer_style(table_row=self.table_row, color=self.layer.suggested_symbol.color(),
                                       symbol_button=self.table_row.icon_field, 
                                       icon_path=self.current_icon_path if not is_default else None,
                                       is_default_symbol=is_default))
        btn.clicked.connect(self.close)

    # sets an icon for an icon button
    def set_icon_for_button(self, btn: SvgButton, pos: int):
        existing_svg_path = create_existing_icon_path(self.layer.suggested_icons[pos])
        temp_icon = create_temp_svg(existing_svg_path, self.layer.suggested_symbol.color().name(), "1", "black", "1",
                                    "2")

        self.icon_btn_style(btn, temp_icon, pos + 1)

        if self.layer.suggested_icon_path in [str(self.layer.suggested_icons[pos]), str(existing_svg_path)]:
            btn.setBorderThickness(3)

        btn.clicked.connect(self.func_for_changing_layer_style_icon(existing_svg_path))
        btn.clicked.connect(self.close)

    def func_for_changing_layer_style_icon(self, svg_path: Path):
        return lambda: change_layer_style(table_row=self.table_row, color=self.layer.suggested_symbol.color(),
                                          symbol_button=self.table_row.icon_field, icon_path=svg_path,
                                          is_default_symbol=False)

    def icon_btn_style(self, btn: SvgButton, temp_icon: str, pos: int):
        btn.setFixedSize(BTN_SIZE)
        self.layout.addWidget(btn, 0, pos)
        self.temp_icons.append(temp_icon)
        btn.setIcon(temp_icon)
        btn.setBorderRadius(10)
        btn.setBackground("transparent")

    def closeEvent(self, event):
        TEMP_ICONS.extend(self.temp_icons)
        self.temp_icons.clear()
        super().closeEvent(event)
    
    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        if event.key() == Qt.Key_Escape:
            self.close()

    def focusOutEvent(self, event):
        super().focusOutEvent(event)
        self.close()


# creates a temporary SVG file out of a svg file path
def create_temp_svg(original_svg_path: Path, fill_color: str, fill_opacity: str, outline_color: str,
                    outline_opacity: str, outline_width: str):
    # Parse the original SVG file
    tree = ET.parse(original_svg_path)
    root = tree.getroot()

    # Find all path elements
    path_elements = root.findall(".//{http://www.w3.org/2000/svg}path")
    circle_elements = root.findall(".//{http://www.w3.org/2000/svg}circle")

    # modify the path elements
    for path_element in path_elements:
        set_element_attributes(path_element, fill_color, fill_opacity, outline_color, outline_opacity, outline_width,
                               "maki\\" in str(original_svg_path) or "maki/" in str(original_svg_path))

    # modify the circle elements
    for circle_element in circle_elements:
        set_element_attributes(circle_element, fill_color, fill_opacity, outline_color, outline_opacity, outline_width,
                               "maki\\" in str(original_svg_path) or "maki/" in str(original_svg_path))

    # Write the modified SVG to a temporary file
    with tempfile.NamedTemporaryFile(delete=False, suffix=".svg") as temp_file:
        file_path = temp_file.name
        tree.write(file_path)

    # Return the temporary file's path
    return file_path


# modifies the attributes of an SVG element
def set_element_attributes(element, fill_color, fill_opacity, outline_color, outline_opacity, outline_width, is_maki):
    element.set("fill", fill_color)
    element.set("fill-opacity", fill_opacity)
    element.set("stroke", outline_color)
    element.set("stroke-opacity", outline_opacity)
    if is_maki:
        element.set("stroke-width", "0.05")
    else:
        element.set("stroke-width", outline_width)


# creates a temporary SVG file out of a default symbol
def create_temp_svg_for_default_symbol(symbol: QgsSymbol, color: QColor = None):
    symbol.setColor(color)
    with tempfile.NamedTemporaryFile(delete=False, suffix=".svg") as temp_file:
        file_path = temp_file.name
        symbol.exportImage(file_path, 'svg', QSize(20, 20))
    return file_path


# changes the style of the suggested_symbol when a change occurs for the color or icon button
def change_layer_style(table_row: TableRow, color: QColor, symbol_button: CustomSymbolButton,
                       color_button: CustomColorButton = None, icon_path=None, is_default_symbol=None):
    layer = table_row.vectorlayer

    layer.suggested_symbol.setColor(color)

    if is_default_symbol is not None:
        layer.is_default_symbol = is_default_symbol

    if color_button is not None:
        color_button.setColor(layer.suggested_symbol.color())
    else:
        if is_default_symbol:
            default_symbol = QgsSymbol.defaultSymbol(layer.qgs_layer.geometryType())
            default_symbol.setColor(layer.suggested_symbol.color())
            default_symbol.setSize(DEFAULT_ICON_SIZE)
            symbol_button.setSymbol(default_symbol)
            layer.suggested_symbol = default_symbol.clone()
            layer.suggested_icon_path = ""
        else:
            layer.suggested_symbol.changeSymbolLayer(0, QgsSvgMarkerSymbolLayer(str(icon_path), 10, 0))
            layer.suggested_symbol.setColor(color)
            cloned_symbol = layer.suggested_symbol.clone()
            cloned_symbol.setSize(DEFAULT_ICON_SIZE + 5)
            symbol_button.setSymbol(cloned_symbol)
            layer.suggested_icon_path = str(icon_path)

        for icon in TEMP_ICONS:
            try:
                os.remove(icon)
            except Exception as e:
                print(e)

        TEMP_ICONS.clear()

    if layer.qgs_layer.wkbType() in [
        QgsWkbTypes.Point,
        QgsWkbTypes.PointM,
        QgsWkbTypes.PointZ,
        QgsWkbTypes.PointZM,
        QgsWkbTypes.Point25D,
        QgsWkbTypes.MultiPoint,
        QgsWkbTypes.MultiPointM,
        QgsWkbTypes.MultiPointZ,
        QgsWkbTypes.MultiPointZM,
        QgsWkbTypes.MultiPoint25D
        ]:
        symbol_button.setColor(layer.suggested_symbol.color())
    else:
        symbol_button.setColor(QColor("gray"))

    table_row.checkbox.setChecked(True)
