"""
Edit mode operations for the hosts TUI application.

This module handles all edit mode functionality including
entry validation, saving, form management, and change detection.
"""

import ipaddress
import re
from textual.widgets import Input, Checkbox, DataTable
from .save_confirmation_modal import SaveConfirmationModal


class EditHandler:
    """Handles all edit mode operations for the hosts manager."""

    def __init__(self, app):
        """Initialize the edit handler with reference to the main app."""
        self.app = app

    def get_current_entry_type(self) -> str:
        """Determine if current entry is 'ip' or 'dns' type."""
        if not self.app.hosts_file.entries or self.app.selected_entry_index >= len(
            self.app.hosts_file.entries
        ):
            return "ip"  # Default to IP type
        
        entry = self.app.hosts_file.entries[self.app.selected_entry_index]
        
        # Check if entry has a DNS name field and it's not empty
        if hasattr(entry, 'dns_name') and entry.dns_name:
            return "dns"
        else:
            return "ip"

    def handle_entry_type_change(self, entry_type: str) -> None:
        """Handle radio button changes and field visibility."""
        if entry_type == "ip":
            # Show IP section, hide DNS section
            self.update_field_visibility(show_ip=True, show_dns=False)
            
            # Focus IP input
            try:
                ip_input = self.app.query_one("#ip-input", Input)
                ip_input.focus()
            except Exception:
                pass
                
        elif entry_type == "dns":
            # Show DNS section, hide IP section
            self.update_field_visibility(show_ip=False, show_dns=True)
            
            # Populate DNS field if we have existing entry data
            try:
                if (self.app.entry_edit_mode and 
                    self.app.hosts_file.entries and 
                    self.app.selected_entry_index < len(self.app.hosts_file.entries)):
                    
                    entry = self.app.hosts_file.entries[self.app.selected_entry_index]
                    dns_input = self.app.query_one("#dns-name-input", Input)
                    
                    # Populate with existing DNS name if available
                    dns_name = getattr(entry, 'dns_name', '') or ''
                    if dns_name and not dns_input.value:  # Only populate if field is empty
                        dns_input.value = dns_name
                    
                    # Focus DNS input
                    dns_input.focus()
                else:
                    # Just focus if no data to populate
                    dns_input = self.app.query_one("#dns-name-input", Input)
                    dns_input.focus()
            except Exception:
                pass

    def update_field_visibility(self, show_ip: bool, show_dns: bool) -> None:
        """Show/hide IP and DNS input sections based on entry type."""
        try:
            ip_section = self.app.query_one("#edit-ip-section")
            dns_section = self.app.query_one("#edit-dns-section")
            
            if show_ip:
                ip_section.remove_class("hidden")
            else:
                ip_section.add_class("hidden")
                
            if show_dns:
                dns_section.remove_class("hidden")
            else:
                dns_section.add_class("hidden")
                
        except Exception:
            # Sections not found, ignore silently
            pass

    def populate_edit_form_with_type_detection(self) -> None:
        """Initialize edit form with correct radio button state and field visibility."""
        if not self.app.entry_edit_mode:
            return
            
        # Use a timer to delay radio button setup to allow widgets to initialize
        self.app.set_timer(0.1, self._delayed_radio_setup)

    def _delayed_radio_setup(self) -> None:
        """Set up radio buttons after a small delay to ensure widgets are ready."""
        if not self.app.entry_edit_mode:
            return
            
        # Determine current entry type
        entry_type = self.get_current_entry_type()
        
        try:
            # Get current entry for DNS field population
            entry = self.app.hosts_file.entries[self.app.selected_entry_index]
            
            # Get radio buttons
            ip_radio = self.app.query_one("#edit-ip-entry-radio")
            dns_radio = self.app.query_one("#edit-dns-entry-radio")
            
            # Set radio button values - let RadioSet manage pressed_button automatically
            if entry_type == "ip":
                # Clear DNS radio first, then set IP radio
                dns_radio.value = False
                ip_radio.value = True
            else:
                # Clear IP radio first, then set DNS radio  
                ip_radio.value = False
                dns_radio.value = True
                
            # Update field visibility
            self.handle_entry_type_change(entry_type)
            
            # Populate DNS name field for DNS entries (after field is visible)
            if entry_type == "dns":
                dns_input = self.app.query_one("#dns-name-input", Input)
                dns_input.value = getattr(entry, 'dns_name', '') or ''
                
        except Exception as e:
            # Debug: Show what went wrong
            self.app.update_status(f"Debug: populate_edit_form error: {e}")

    def has_entry_changes(self) -> bool:
        """Check if the current entry has been modified from its original values."""
        if not self.app.original_entry_values or not self.app.entry_edit_mode:
            return False

        # Get current values from form fields
        ip_input = self.app.query_one("#ip-input", Input)
        hostname_input = self.app.query_one("#hostname-input", Input)
        comment_input = self.app.query_one("#comment-input", Input)
        active_checkbox = self.app.query_one("#active-checkbox", Checkbox)
        
        # Try to get DNS input - may not exist in all contexts
        try:
            dns_input = self.app.query_one("#dns-name-input", Input)
            dns_value = dns_input.value.strip()
        except Exception:
            dns_value = ""

        current_hostnames = [
            h.strip() for h in hostname_input.value.split(",") if h.strip()
        ]
        current_comment = comment_input.value.strip() or None

        # Compare with original values
        return (
            ip_input.value.strip() != self.app.original_entry_values["ip_address"]
            or dns_value != (self.app.original_entry_values.get("dns_name") or "")
            or current_hostnames != self.app.original_entry_values["hostnames"]
            or current_comment != self.app.original_entry_values["comment"]
            or active_checkbox.value != self.app.original_entry_values["is_active"]
        )

    def exit_edit_entry_with_confirmation(self) -> None:
        """Exit entry edit mode and return focus to the entries table."""
        if not self.app.entry_edit_mode:
            return

        # Check if there are unsaved changes
        if self.has_entry_changes():
            # Show save confirmation modal
            def handle_save_confirmation(result):
                if result == "save":
                    # Validate and save changes
                    if self.validate_and_save_entry_changes():
                        self.exit_edit_entry_mode()
                elif result == "discard":
                    # Restore original values and exit
                    self.restore_original_entry_values()
                    self.exit_edit_entry_mode()
                elif result == "cancel":
                    # Do nothing, stay in edit mode
                    pass

            self.app.push_screen(SaveConfirmationModal(), handle_save_confirmation)
        else:
            # No changes, exit directly
            self.exit_edit_entry_mode()

    def exit_edit_entry_mode(self) -> None:
        """Helper method to exit entry edit mode and clean up."""
        self.app.entry_edit_mode = False
        self.app.original_entry_values = None
        self.app.details_handler.update_entry_details()

        # Return focus to the entries table
        table = self.app.query_one("#entries-table", DataTable)
        table.focus()

        self.app.update_status("Exited entry edit mode")

    def restore_original_entry_values(self) -> None:
        """Restore the original values to the form fields."""
        if not self.app.original_entry_values:
            return

        # Update form fields with original values
        ip_input = self.app.query_one("#ip-input", Input)
        hostname_input = self.app.query_one("#hostname-input", Input)
        comment_input = self.app.query_one("#comment-input", Input)
        active_checkbox = self.app.query_one("#active-checkbox", Checkbox)
        
        # Try to get DNS input - may not exist in all contexts
        try:
            dns_input = self.app.query_one("#dns-name-input", Input)
            dns_input.value = self.app.original_entry_values.get("dns_name") or ""
        except Exception:
            pass  # DNS input not available

        ip_input.value = self.app.original_entry_values["ip_address"]
        hostname_input.value = ", ".join(self.app.original_entry_values["hostnames"])
        comment_input.value = self.app.original_entry_values["comment"] or ""
        active_checkbox.value = self.app.original_entry_values["is_active"]

        # Restore radio button state and field visibility
        try:
            dns_name = self.app.original_entry_values.get("dns_name")
            ip_radio = self.app.query_one("#edit-ip-entry-radio")
            dns_radio = self.app.query_one("#edit-dns-entry-radio")
            
            if dns_name:
                # Was DNS entry - set DNS radio and show DNS field
                ip_radio.value = False
                dns_radio.value = True
                self.handle_entry_type_change("dns")
            else:
                # Was IP entry - set IP radio and show IP field
                dns_radio.value = False
                ip_radio.value = True
                self.handle_entry_type_change("ip")
        except Exception:
            pass  # Radio widgets not available

    def validate_entry_by_type(self, entry_type: str) -> bool:
        """Type-specific validation for IP or DNS entries."""
        hostname_input = self.app.query_one("#hostname-input", Input)
        
        # Validate hostname(s) - common to both types
        hostnames = [h.strip() for h in hostname_input.value.split(",") if h.strip()]
        if not hostnames:
            self.app.update_status("❌ At least one hostname is required - changes not saved")
            return False

        hostname_pattern = re.compile(
            r"^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$"
        )

        for hostname in hostnames:
            if not hostname_pattern.match(hostname):
                self.app.update_status(f"❌ Invalid hostname: {hostname} - changes not saved")
                return False
        
        if entry_type == "ip":
            # Validate IP address
            try:
                ip_input = self.app.query_one("#ip-input", Input)
                ip_address = ip_input.value.strip()
                if not ip_address:
                    self.app.update_status("❌ IP address is required - changes not saved")
                    return False
                ipaddress.ip_address(ip_address)
            except ValueError:
                self.app.update_status("❌ Invalid IP address - changes not saved")
                return False
        elif entry_type == "dns":
            # Validate DNS name
            try:
                dns_input = self.app.query_one("#dns-name-input", Input)
                dns_name = dns_input.value.strip()
                if not dns_name:
                    self.app.update_status("❌ DNS name is required - changes not saved")
                    return False
                
                # Basic DNS name validation
                if (
                    " " in dns_name
                    or not dns_name.replace(".", "").replace("-", "").isalnum()
                    or dns_name.startswith(".")
                    or dns_name.endswith(".")
                    or ".." in dns_name
                ):
                    self.app.update_status("❌ Invalid DNS name format - changes not saved")
                    return False
            except Exception:
                self.app.update_status("❌ DNS name validation failed - changes not saved")
                return False
        
        return True

    def validate_and_save_entry_changes(self) -> bool:
        """Validate current entry values and save if valid."""
        if not self.app.hosts_file.entries or self.app.selected_entry_index >= len(
            self.app.hosts_file.entries
        ):
            return False

        entry = self.app.hosts_file.entries[self.app.selected_entry_index]

        # Determine current entry type based on radio selection
        try:
            radio_set = self.app.query_one("#edit-entry-type-radio")
            pressed_radio = radio_set.pressed_button
            if pressed_radio and pressed_radio.id == "edit-dns-entry-radio":
                entry_type = "dns"
            else:
                entry_type = "ip"
        except Exception:
            # Fallback to existing entry type detection
            entry_type = self.get_current_entry_type()

        # Type-specific validation
        if not self.validate_entry_by_type(entry_type):
            return False

        # Get common form values
        hostname_input = self.app.query_one("#hostname-input", Input)
        comment_input = self.app.query_one("#comment-input", Input)
        active_checkbox = self.app.query_one("#active-checkbox", Checkbox)

        hostnames = [h.strip() for h in hostname_input.value.split(",") if h.strip()]
        comment = comment_input.value.strip() or None
        is_active = active_checkbox.value

        # Update entry based on type
        if entry_type == "ip":
            # IP entry - update IP address and clear DNS fields
            ip_input = self.app.query_one("#ip-input", Input)
            entry.ip_address = ip_input.value.strip()
            entry.dns_name = None  # Clear DNS name when converting to IP
            # Clear DNS-related fields
            if hasattr(entry, 'resolved_ip'):
                entry.resolved_ip = None
            if hasattr(entry, 'last_resolved'):
                entry.last_resolved = None
            if hasattr(entry, 'dns_resolution_status'):
                entry.dns_resolution_status = None
        else:
            # DNS entry - update DNS name and set placeholder IP
            dns_input = self.app.query_one("#dns-name-input", Input)
            entry.dns_name = dns_input.value.strip()
            entry.ip_address = "0.0.0.0"  # Placeholder IP for DNS entries
            # Initialize DNS fields if they don't exist
            if not hasattr(entry, 'resolved_ip'):
                entry.resolved_ip = None
            if not hasattr(entry, 'last_resolved'):
                entry.last_resolved = None
            if not hasattr(entry, 'dns_resolution_status'):
                from ..core.dns import DNSResolutionStatus
                entry.dns_resolution_status = DNSResolutionStatus.NOT_RESOLVED

        # Update common fields
        entry.hostnames = hostnames
        entry.comment = comment
        entry.is_active = is_active

        # Save to file
        success, message = self.app.manager.save_hosts_file(self.app.hosts_file)
        if success:
            # Update the table display
            self.app.table_handler.populate_entries_table()
            # Restore cursor position
            table = self.app.query_one("#entries-table", DataTable)
            display_index = self.app.table_handler.actual_index_to_display_index(
                self.app.selected_entry_index
            )
            if table.row_count > 0 and display_index < table.row_count:
                table.move_cursor(row=display_index)
            
            # Provide appropriate success message
            if entry_type == "dns":
                self.app.update_status("DNS entry saved successfully - DNS resolution can be triggered manually")
            else:
                self.app.update_status("Entry saved successfully")
            return True
        else:
            self.app.update_status(f"❌ Error saving entry: {message}")
            return False

    def navigate_to_next_field(self) -> None:
        """Move to the next field in edit mode."""
        if not self.app.entry_edit_mode:
            return

        # Get all input fields in order, including radio set and dynamic DNS field
        try:
            radio_set = self.app.query_one("#edit-entry-type-radio")
            hostname_input = self.app.query_one("#hostname-input", Input)
            comment_input = self.app.query_one("#comment-input", Input)
            active_checkbox = self.app.query_one("#active-checkbox", Checkbox)
            
            # Build field list based on current entry type
            fields = [radio_set]
            
            # Add IP or DNS field based on visibility
            try:
                ip_section = self.app.query_one("#edit-ip-section")
                if not ip_section.has_class("hidden"):
                    ip_input = self.app.query_one("#ip-input", Input)
                    fields.append(ip_input)
            except Exception:
                pass
                
            try:
                dns_section = self.app.query_one("#edit-dns-section")
                if not dns_section.has_class("hidden"):
                    dns_input = self.app.query_one("#dns-name-input", Input)
                    fields.append(dns_input)
            except Exception:
                pass
            
            # Add remaining fields
            fields.extend([hostname_input, comment_input, active_checkbox])

            # Find currently focused field and move to next
            for i, field in enumerate(fields):
                if field.has_focus:
                    next_field = fields[(i + 1) % len(fields)]
                    next_field.focus()
                    break
                    
        except Exception:
            # Fallback to original navigation if widgets not ready
            pass

    def navigate_to_prev_field(self) -> None:
        """Move to the previous field in edit mode."""
        if not self.app.entry_edit_mode:
            return

        # Get all input fields in order, including radio set and dynamic DNS field
        try:
            radio_set = self.app.query_one("#edit-entry-type-radio")
            hostname_input = self.app.query_one("#hostname-input", Input)
            comment_input = self.app.query_one("#comment-input", Input)
            active_checkbox = self.app.query_one("#active-checkbox", Checkbox)
            
            # Build field list based on current entry type
            fields = [radio_set]
            
            # Add IP or DNS field based on visibility
            try:
                ip_section = self.app.query_one("#edit-ip-section")
                if not ip_section.has_class("hidden"):
                    ip_input = self.app.query_one("#ip-input", Input)
                    fields.append(ip_input)
            except Exception:
                pass
                
            try:
                dns_section = self.app.query_one("#edit-dns-section")
                if not dns_section.has_class("hidden"):
                    dns_input = self.app.query_one("#dns-name-input", Input)
                    fields.append(dns_input)
            except Exception:
                pass
            
            # Add remaining fields
            fields.extend([hostname_input, comment_input, active_checkbox])

            # Find currently focused field and move to previous
            for i, field in enumerate(fields):
                if field.has_focus:
                    prev_field = fields[(i - 1) % len(fields)]
                    prev_field.focus()
                    break
                    
        except Exception:
            # Fallback to original navigation if widgets not ready
            pass

    def handle_entry_edit_key_event(self, event) -> bool:
        """Handle key events for entry edit mode navigation.

        Returns True if the event was handled, False otherwise.
        """
        # Only handle custom tab navigation if in entry edit mode AND no modal is open
        if self.app.entry_edit_mode and len(self.app.screen_stack) == 1:
            if event.key == "tab":
                # Prevent default tab behavior and use our custom navigation
                event.prevent_default()
                self.navigate_to_next_field()
                return True
            elif event.key == "shift+tab":
                # Prevent default shift+tab behavior and use our custom navigation
                event.prevent_default()
                self.navigate_to_prev_field()
                return True

        return False
