# environments_dialog.py
#
# Copyright 2025 Pavel Baksy
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later

import re
from gi.repository import Adw, Gtk, GObject
from .widgets.variable_row import VariableRow
from .widgets.environment_row import EnvironmentRow
from .widgets.environment_header_row import EnvironmentHeaderRow
from .widgets.variable_data_row import VariableDataRow


@Gtk.Template(resource_path='/cz/bugsy/roster/environments-dialog.ui')
class EnvironmentsDialog(Adw.Dialog):
    """Dialog for managing project environments and variables."""

    __gtype_name__ = 'EnvironmentsDialog'

    table_container = Gtk.Template.Child()
    add_environment_button = Gtk.Template.Child()

    __gsignals__ = {
        'environments-updated': (GObject.SIGNAL_RUN_FIRST, None, ()),
    }

    def __init__(self, project, project_manager, recently_updated_variables=None):
        super().__init__()
        self.project = project
        self.project_manager = project_manager
        self.recently_updated_variables = recently_updated_variables or {}
        self.size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        self.header_row = None
        self.data_rows = []
        self._populate_table()

    def _populate_table(self):
        """Populate the transposed environment-variable table."""
        # Clear existing
        while child := self.table_container.get_first_child():
            self.table_container.remove(child)

        self.data_rows = []

        # Create header row
        self.header_row = EnvironmentHeaderRow(
            self.project.environments,
            self.size_group
        )
        self.header_row.connect('environment-edit-requested',
                               self._on_environment_edit)
        self.header_row.connect('environment-delete-requested',
                               self._on_environment_delete)
        self.header_row.connect('environment-copy-requested',
                               self._on_environment_copy)
        self.table_container.append(self.header_row)

        # Add separator
        separator = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
        self.table_container.append(separator)

        # Create data rows for each variable
        for var_name in self.project.variable_names:
            # Check if variable was recently updated
            update_timestamp = self.recently_updated_variables.get(var_name)

            row = VariableDataRow(
                var_name,
                self.project.environments,
                self.size_group,
                self.project,
                self.project_manager,
                update_timestamp=update_timestamp
            )
            row.connect('variable-changed',
                       self._on_variable_changed, var_name, row)
            row.connect('variable-delete-requested',
                       self._on_variable_remove, var_name)
            row.connect('value-changed',
                       self._on_value_changed, var_name)
            row.connect('sensitivity-changed',
                       self._on_sensitivity_changed, var_name)

            self.table_container.append(row)
            self.data_rows.append(row)

        # Add "Add Variable" button row at the bottom
        add_var_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
        add_var_row.set_margin_start(12)
        add_var_row.set_margin_end(12)
        add_var_row.set_margin_top(6)
        add_var_row.set_margin_bottom(6)

        # Variable cell with add button
        var_cell = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
        var_cell.set_size_request(150, -1)
        if self.size_group:
            self.size_group.add_widget(var_cell)

        add_variable_button = Gtk.Button()
        add_variable_button.set_icon_name("list-add-symbolic")
        add_variable_button.set_tooltip_text("Add variable")
        add_variable_button.connect('clicked', self.on_add_variable_clicked)
        add_variable_button.add_css_class("flat")
        add_variable_button.add_css_class("circular")

        var_cell.append(add_variable_button)
        add_var_row.append(var_cell)

        # Empty space for value columns
        empty_space = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        empty_space.set_hexpand(True)
        add_var_row.append(empty_space)

        self.table_container.append(add_var_row)

    def on_add_variable_clicked(self, button):
        """Add new variable."""
        dialog = Adw.AlertDialog()
        dialog.set_heading("New Variable")
        dialog.set_body("Enter variable name:")

        entry = Gtk.Entry()
        entry.set_placeholder_text("Variable name")
        entry.set_activates_default(True)
        dialog.set_extra_child(entry)

        dialog.add_response("cancel", "Cancel")
        dialog.add_response("add", "Add")
        dialog.set_response_appearance("add", Adw.ResponseAppearance.SUGGESTED)
        dialog.set_default_response("add")
        dialog.set_close_response("cancel")

        def on_response(dlg, response):
            if response == "add":
                name = entry.get_text().strip()
                if name and name not in self.project.variable_names:
                    self.project_manager.add_variable(self.project.id, name)
                    # Reload project data
                    self._reload_project()
                    self._populate_table()
                    self.emit('environments-updated')

        dialog.connect("response", on_response)
        dialog.present(self)

    def _on_variable_remove(self, widget, var_name):
        """Remove variable with confirmation."""
        dialog = Adw.AlertDialog()
        dialog.set_heading("Delete Variable?")
        dialog.set_body(f"Delete variable '{var_name}' from all environments? This cannot be undone.")

        dialog.add_response("cancel", "Cancel")
        dialog.add_response("delete", "Delete")
        dialog.set_response_appearance("delete", Adw.ResponseAppearance.DESTRUCTIVE)
        dialog.set_close_response("cancel")

        def on_response(dlg, response):
            if response == "delete":
                def on_delete_complete():
                    self._reload_project()
                    self._populate_table()
                    self.emit('environments-updated')

                self.project_manager.delete_variable(self.project.id, var_name, on_delete_complete)

        dialog.connect("response", on_response)
        dialog.present(self)

    def _on_variable_changed(self, widget, old_name, row):
        """Handle variable name change."""
        new_name = row.get_variable_name()
        if new_name and new_name != old_name and new_name not in self.project.variable_names:
            def on_rename_complete():
                self._reload_project()
                self._populate_table()
                self.emit('environments-updated')

            self.project_manager.rename_variable(self.project.id, old_name, new_name, on_rename_complete)

    @Gtk.Template.Callback()
    def on_add_environment_clicked(self, button):
        """Add new environment."""
        dialog = Adw.AlertDialog()
        dialog.set_heading("New Environment")
        dialog.set_body("Enter environment name:")

        entry = Gtk.Entry()
        entry.set_placeholder_text("Environment name (e.g., Production)")
        entry.set_activates_default(True)
        dialog.set_extra_child(entry)

        dialog.add_response("cancel", "Cancel")
        dialog.add_response("add", "Add")
        dialog.set_response_appearance("add", Adw.ResponseAppearance.SUGGESTED)
        dialog.set_default_response("add")
        dialog.set_close_response("cancel")

        def on_response(dlg, response):
            if response == "add":
                name = entry.get_text().strip()
                if name:
                    self.project_manager.add_environment(self.project.id, name)
                    self._reload_project()
                    self._populate_table()
                    self.emit('environments-updated')

        dialog.connect("response", on_response)
        dialog.present(self)

    def _on_environment_edit(self, widget, environment):
        """Edit environment name."""
        dialog = Adw.AlertDialog()
        dialog.set_heading("Edit Environment")
        dialog.set_body("Enter new name:")

        entry = Gtk.Entry()
        entry.set_text(environment.name)
        entry.set_activates_default(True)
        dialog.set_extra_child(entry)

        dialog.add_response("cancel", "Cancel")
        dialog.add_response("save", "Save")
        dialog.set_response_appearance("save", Adw.ResponseAppearance.SUGGESTED)
        dialog.set_default_response("save")
        dialog.set_close_response("cancel")

        def on_response(dlg, response):
            if response == "save":
                new_name = entry.get_text().strip()
                if new_name:
                    self.project_manager.update_environment(self.project.id, environment.id, name=new_name)
                    self._reload_project()
                    self._populate_table()
                    self.emit('environments-updated')

        dialog.connect("response", on_response)
        dialog.present(self)

    def _on_environment_copy(self, widget, environment):
        """Copy an environment with a unique name."""
        existing_names = {env.name for env in self.project.environments}
        new_name = self._unique_env_name(environment.name, existing_names)

        def on_copy_complete(new_env):
            self._reload_project()
            self._populate_table()
            self.emit('environments-updated')

        self.project_manager.copy_environment(self.project.id, environment.id, new_name, on_copy_complete)

    @staticmethod
    def _unique_env_name(base_name, existing_names):
        """Generate a unique environment name by appending (1), (2), etc."""
        match = re.match(r'^(.*?) \((\d+)\)$', base_name)
        base = match.group(1) if match else base_name
        counter = 1
        while True:
            candidate = f"{base} ({counter})"
            if candidate not in existing_names:
                return candidate
            counter += 1

    def _on_environment_delete(self, widget, environment):
        """Delete environment with confirmation."""
        # Prevent deletion of last environment
        if len(self.project.environments) <= 1:
            dialog = Adw.AlertDialog()
            dialog.set_heading("Cannot Delete")
            dialog.set_body("Each project must have at least one environment.")
            dialog.add_response("ok", "OK")
            dialog.present(self)
            return

        dialog = Adw.AlertDialog()
        dialog.set_heading("Delete Environment?")
        dialog.set_body(f"Delete environment '{environment.name}'? This cannot be undone.")

        dialog.add_response("cancel", "Cancel")
        dialog.add_response("delete", "Delete")
        dialog.set_response_appearance("delete", Adw.ResponseAppearance.DESTRUCTIVE)
        dialog.set_close_response("cancel")

        def on_response(dlg, response):
            if response == "delete":
                def on_delete_complete():
                    self._reload_project()
                    self._populate_table()
                    self.emit('environments-updated')

                self.project_manager.delete_environment(self.project.id, environment.id, on_delete_complete)

        dialog.connect("response", on_response)
        dialog.present(self)

    def _on_value_changed(self, widget, env_id, value, var_name):
        """Handle value change in table cell."""
        # Note: value is already stored by VariableDataRow using set_variable_value
        # This handler is just for emitting the update signal
        self.emit('environments-updated')

    def _on_sensitivity_changed(self, widget, is_sensitive, var_name):
        """Handle variable sensitivity toggle."""
        def on_complete(success):
            if success:
                # Reload and refresh UI
                self._reload_project()
                self._populate_table()
                self.emit('environments-updated')

        if is_sensitive:
            # Mark as sensitive (move to keyring)
            self.project_manager.mark_variable_as_sensitive(self.project.id, var_name, on_complete)
        else:
            # Mark as non-sensitive (move to JSON)
            self.project_manager.mark_variable_as_nonsensitive(self.project.id, var_name, on_complete)

    def _reload_project(self):
        """Reload project data from manager."""
        projects = self.project_manager.load_projects()
        for p in projects:
            if p.id == self.project.id:
                self.project = p
                break
