import logging
from PyQt5 import uic
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtWidgets import QWidget, QPushButton, QGridLayout, QVBoxLayout, QLineEdit

from lib.helpers import get_resource
from ui.widget import Widget


class VirtualKeyboard(Widget):
    """
    A custom virtual keyboard widget for text input.
    This can be used with QLineEdit widgets to provide on-screen keyboard functionality.
    """

    # Signal emitted when a key is pressed
    key_pressed = pyqtSignal(str)

    def __init__(self, target_input=None):
        """
        Initialize the virtual keyboard.

        Args:
            target_input (QLineEdit, optional): The QLineEdit widget to receive input.
        """
        # Skip the Widget.__init__ UI loading and initialize QWidget directly
        QWidget.__init__(self)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setWindowTitle('VirtualKeyboard')
        self.log = logging.getLogger(f"{self.__class__.__name__} ({id(self)})")

        self.target_input = target_input
        self.init_ui()

    def init_ui(self):
        """Initialize the user interface."""
        # Create the main layout
        main_layout = QVBoxLayout()
        self.setLayout(main_layout)

        # Create the display area (optional, for standalone use)
        self.display = QLineEdit()
        self.display.setReadOnly(True)
        main_layout.addWidget(self.display)

        # Create the keyboard layout
        keyboard_layout = QGridLayout()
        main_layout.addLayout(keyboard_layout)

        # Define the keyboard layout
        keys = [
            ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
            ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'],
            ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],
            ['z', 'x', 'c', 'v', 'b', 'n', 'm', '.', '-', '_']
        ]

        # Create the keys
        for row, key_row in enumerate(keys):
            for col, key in enumerate(key_row):
                button = QPushButton(key)
                button.clicked.connect(lambda checked, k=key: self.key_click(k))
                keyboard_layout.addWidget(button, row, col)

        # Add special keys
        # Space
        space_button = QPushButton('Space')
        space_button.clicked.connect(lambda: self.key_click(' '))
        keyboard_layout.addWidget(space_button, 4, 2, 1, 4)

        # Backspace
        backspace_button = QPushButton('Backspace')
        backspace_button.clicked.connect(self.backspace)
        keyboard_layout.addWidget(backspace_button, 4, 6, 1, 2)

        # Shift
        self.shift_button = QPushButton('Shift')
        self.shift_button.setCheckable(True)
        self.shift_button.clicked.connect(self.toggle_shift)
        keyboard_layout.addWidget(self.shift_button, 4, 0, 1, 2)

        # Enter
        enter_button = QPushButton('Enter')
        enter_button.clicked.connect(self.enter)
        keyboard_layout.addWidget(enter_button, 4, 8, 1, 2)

        # Set window properties
        self.setWindowTitle('Virtual Keyboard')
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.Tool)

    def set_target(self, target_input):
        """
        Set the target input widget.

        Args:
            target_input (QLineEdit): The QLineEdit widget to receive input.
        """
        self.target_input = target_input

    def key_click(self, key):
        """
        Handle key clicks.

        Args:
            key (str): The key that was clicked.
        """
        # Apply shift if active
        if self.shift_button.isChecked():
            key = key.upper()
            self.shift_button.setChecked(False)

        # Emit the key pressed signal
        self.key_pressed.emit(key)

        # Update the target input if available
        if self.target_input:
            current_text = self.target_input.text()
            cursor_pos = self.target_input.cursorPosition()
            new_text = current_text[:cursor_pos] + key + current_text[cursor_pos:]
            self.target_input.setText(new_text)
            self.target_input.setCursorPosition(cursor_pos + 1)

        # Update the display
        self.display.setText(self.display.text() + key)

    def backspace(self):
        """Handle backspace key."""
        if self.target_input:
            current_text = self.target_input.text()
            cursor_pos = self.target_input.cursorPosition()
            if cursor_pos > 0:
                new_text = current_text[:cursor_pos-1] + current_text[cursor_pos:]
                self.target_input.setText(new_text)
                self.target_input.setCursorPosition(cursor_pos - 1)

        # Update the display
        display_text = self.display.text()
        if display_text:
            self.display.setText(display_text[:-1])

    def toggle_shift(self):
        """Toggle shift key state."""
        pass  # The state is handled by the button's checkable property

    def enter(self):
        """Handle enter key."""
        self.close()

    def attach_to_line_edit(self, line_edit):
        """
        Attach the virtual keyboard to a QLineEdit.

        Args:
            line_edit (QLineEdit): The QLineEdit to attach to.
        """
        self.set_target(line_edit)
        line_edit.setFocus()

        # Position the keyboard near the line edit
        global_pos = line_edit.mapToGlobal(line_edit.rect().bottomLeft())
        self.move(global_pos.x(), global_pos.y() + 10)

        self.show()


def show_virtual_keyboard(line_edit):
    """
    Show a virtual keyboard for the given QLineEdit.

    Args:
        line_edit (QLineEdit): The QLineEdit to attach the keyboard to.

    Returns:
        VirtualKeyboard: The virtual keyboard instance.
    """
    keyboard = VirtualKeyboard()
    keyboard.attach_to_line_edit(line_edit)
    return keyboard