"""Griddle GUI - A PySide6 GUI version of the Waffle word puzzle game.

This GUI application provides a visual interface for the Griddle game,
allowing players to click on cells to swap letters and solve the puzzle.
"""

import os
import sys
from PySide6.QtWidgets import (
    QApplication,
    QMainWindow,
    QWidget,
    QVBoxLayout,
    QHBoxLayout,
    QGridLayout,
    QPushButton,
    QLabel,
    QMessageBox,
    QFrame,
)
from PySide6.QtCore import Qt
from PySide6.QtGui import QFont

from file_utils import read_file, write_log, check_grid, print_log
from word_utils import update_grid, swap_cells, check_swap, is_solved


class GriddleGUI(QMainWindow):
    """GUI application for the Griddle word puzzle game."""

    def __init__(self, starter_file="starter.txt", solution_file="solution.txt"):
        """Initialize the Griddle GUI.

        Args:
            starter_file: Path to starter grid file
            solution_file: Path to solution grid file
        """
        super().__init__()

        # Make paths relative to this module's directory if not absolute
        if not os.path.isabs(starter_file):
            starter_file = os.path.join(os.path.dirname(__file__), starter_file)
        if not os.path.isabs(solution_file):
            solution_file = os.path.join(os.path.dirname(__file__), solution_file)

        # Load game
        starter, solution = self.load_game(starter_file, solution_file)
        if starter is None or solution is None:
            QMessageBox.critical(self, "Error", "Failed to load game files!")
            sys.exit(1)

        # Initialize game state
        self.starter = starter
        self.solution = solution
        self.current = starter.copy()
        self.swap_count = 0
        self.selected_cell = None
        self.cell_buttons = []

        # Setup GUI
        self.setup_gui()
        self.update_display()

    def load_game(self, starter_file, solution_file):
        """Load the starter and solution grids from files.

        Args:
            starter_file (str): Path to the starter grid file.
            solution_file (str): Path to the solution grid file.

        Returns:
            tuple: (starter_grid, solution_grid)

        Raises:
            ValueError: If either grid is invalid.
        """
        starter = read_file(starter_file)
        solution = read_file(solution_file)

        # Validate grids
        starter_check = check_grid(starter)
        solution_check = check_grid(solution)

        if starter_check != "valid":
            raise ValueError(f"Starter grid is invalid ({starter_check})")
        if solution_check != "valid":
            raise ValueError(f"Solution grid is invalid ({solution_check})")

        return starter, solution

    def setup_gui(self):
        """Setup the GUI components."""
        self.setWindowTitle("Griddle - Waffle Word Puzzle")
        self.setFixedSize(700, 850)

        # Central widget and main layout
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        main_layout.setSpacing(15)
        main_layout.setContentsMargins(20, 20, 20, 20)

        # Title
        title_label = QLabel("GRIDDLE")
        title_font = QFont("Arial", 32, QFont.Bold)
        title_label.setFont(title_font)
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet("color: #2c3e50;")
        main_layout.addWidget(title_label)

        # Subtitle
        subtitle_label = QLabel("Swap letters to form valid words in all rows and columns")
        subtitle_font = QFont("Arial", 12)
        subtitle_label.setFont(subtitle_font)
        subtitle_label.setAlignment(Qt.AlignCenter)
        subtitle_label.setStyleSheet("color: #7f8c8d;")
        main_layout.addWidget(subtitle_label)

        # Swap counter
        self.swap_label = QLabel("Swaps: 0")
        swap_font = QFont("Arial", 16, QFont.Bold)
        self.swap_label.setFont(swap_font)
        self.swap_label.setAlignment(Qt.AlignCenter)
        self.swap_label.setStyleSheet("color: #e74c3c;")
        main_layout.addWidget(self.swap_label)

        # Grid frame
        grid_frame = QFrame()
        grid_frame.setFrameStyle(QFrame.Box | QFrame.Raised)
        grid_frame.setLineWidth(3)
        grid_frame.setStyleSheet("background-color: #ecf0f1;")
        grid_layout_container = QHBoxLayout(grid_frame)

        # Grid layout for buttons
        grid_layout = QGridLayout()
        grid_layout.setSpacing(5)

        # Create grid buttons
        button_font = QFont("Arial", 24, QFont.Bold)
        for i in range(25):
            row = i // 5
            col = i % 5

            btn = QPushButton("")
            btn.setFont(button_font)
            btn.setFixedSize(80, 80)
            btn.clicked.connect(lambda checked, idx=i: self.on_cell_click(idx))
            btn.setStyleSheet("""
                QPushButton {
                    border: 3px solid #95a5a6;
                    border-radius: 5px;
                }
                QPushButton:hover {
                    border: 3px solid #34495e;
                }
            """)
            grid_layout.addWidget(btn, row, col)
            self.cell_buttons.append(btn)

        grid_layout_container.addLayout(grid_layout)
        main_layout.addWidget(grid_frame)

        # Legend
        legend_frame = QFrame()
        legend_frame.setFrameStyle(QFrame.Box)
        legend_frame.setLineWidth(2)
        legend_frame.setStyleSheet("background-color: #ecf0f1;")
        legend_layout = QVBoxLayout(legend_frame)
        legend_layout.setSpacing(5)
        legend_layout.setContentsMargins(20, 10, 20, 10)

        legend_title = QLabel("COLOR GUIDE")
        legend_title_font = QFont("Arial", 12, QFont.Bold)
        legend_title.setFont(legend_title_font)
        legend_title.setStyleSheet("color: #2c3e50;")
        legend_title.setAlignment(Qt.AlignCenter)
        legend_layout.addWidget(legend_title)

        legends = [
            ("● [A] Correct position", "#27ae60"),
            ("● (A) Correct row/column, wrong position", "#f39c12"),
            ("● _A_ Not in correct row/column", "#e74c3c"),
            ("● Empty cell", "#bdc3c7"),
        ]

        legend_font = QFont("Arial", 10)
        for text, color in legends:
            label = QLabel(text)
            label.setFont(legend_font)
            label.setStyleSheet(f"color: {color};")
            legend_layout.addWidget(label)

        main_layout.addWidget(legend_frame)

        # Control buttons
        button_layout = QHBoxLayout()
        button_layout.setSpacing(15)

        button_font = QFont("Arial", 12, QFont.Bold)

        reset_btn = QPushButton("Reset Game")
        reset_btn.setFont(button_font)
        reset_btn.setFixedSize(140, 50)
        reset_btn.setStyleSheet("""
            QPushButton {
                background-color: #3498db;
                color: white;
                border-radius: 5px;
                padding: 10px;
            }
            QPushButton:hover {
                background-color: #2980b9;
            }
        """)
        reset_btn.clicked.connect(self.reset_game)
        button_layout.addWidget(reset_btn)

        log_btn = QPushButton("Show Moves")
        log_btn.setFont(button_font)
        log_btn.setFixedSize(140, 50)
        log_btn.setStyleSheet("""
            QPushButton {
                background-color: #9b59b6;
                color: white;
                border-radius: 5px;
                padding: 10px;
            }
            QPushButton:hover {
                background-color: #8e44ad;
            }
        """)
        log_btn.clicked.connect(self.show_moves)
        button_layout.addWidget(log_btn)

        quit_btn = QPushButton("Quit")
        quit_btn.setFont(button_font)
        quit_btn.setFixedSize(140, 50)
        quit_btn.setStyleSheet("""
            QPushButton {
                background-color: #95a5a6;
                color: white;
                border-radius: 5px;
                padding: 10px;
            }
            QPushButton:hover {
                background-color: #7f8c8d;
            }
        """)
        quit_btn.clicked.connect(self.quit_game)
        button_layout.addWidget(quit_btn)

        main_layout.addLayout(button_layout)

        # Status bar
        self.status_label = QLabel("Click on two cells to swap them")
        status_font = QFont("Arial", 10)
        self.status_label.setFont(status_font)
        self.status_label.setStyleSheet("""
            background-color: #ecf0f1;
            color: #7f8c8d;
            padding: 5px;
            border: 1px solid #bdc3c7;
        """)
        self.status_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        main_layout.addWidget(self.status_label)

    def get_cell_color(self, color_name):
        """Convert color name to hex color code.

        Args:
            color_name: One of "GREEN", "YELLOW", "RED", "WHITE

        Returns:
            Hex color code as string
        """
        color_map = {"GREEN": "#27ae60", "YELLOW": "#f39c12", "RED": "#e74c3c", "WHITE": "#bdc3c7"}
        return color_map.get(color_name, "#ecf0f1")

    def update_display(self):
        """Update the grid display with current game state."""
        colored_grid = update_grid(self.current, self.solution)

        for i, cell in enumerate(colored_grid):
            letter = cell[0]
            color = cell[1] if len(cell) > 1 else "WHITE"

            btn = self.cell_buttons[i]

            # Add borders based on color
            if letter == "_":
                display_text = ""
            elif color == "GREEN":
                display_text = f"[{letter}]"
            elif color == "YELLOW":
                display_text = f"({letter})"
            elif color == "RED":
                display_text = f"_{letter}_"
            else:  # WHITE
                display_text = letter

            btn.setText(display_text)

            bg_color = self.get_cell_color(color)
            text_color = "white" if color != "WHITE" else "#34495e"

            # Highlight selected cell
            if i == self.selected_cell:
                border_style = "border: 5px solid #34495e;"
            else:
                border_style = "border: 3px solid #95a5a6;"

            btn.setStyleSheet(f"""
                QPushButton {{
                    background-color: {bg_color};
                    color: {text_color};
                    {border_style}
                    border-radius: 5px;
                }}
                QPushButton:hover {{
                    border: 3px solid #34495e;
                }}
            """)

        # Update swap counter
        self.swap_label.setText(f"Swaps: {self.swap_count}")

        # Check if solved
        if is_solved(self.current, self.solution):
            self.show_victory()
        elif self.swap_count > 15:
            self.show_game_over()

    def on_cell_click(self, index):
        """Handle cell click event."""
        # Convert index to letter
        letter = chr(ord("a") + index)

        # Check if this is a valid swap letter
        invalid_letters = {"g", "i", "q", "s"}
        if letter in invalid_letters or letter > "x":
            self.status_label.setText(f"Cannot select cell '{letter}' (invalid index)")
            return

        if self.selected_cell is None:
            # First cell selected
            self.selected_cell = index
            self.status_label.setText(f"Selected '{letter}' - Click another cell to swap")
            self.update_display()
        else:
            # Second cell selected - perform swap
            first_letter = chr(ord("a") + self.selected_cell)
            second_letter = letter

            if self.selected_cell == index:
                # Deselect if clicking same cell
                self.selected_cell = None
                self.status_label.setText("Selection cancelled - Click a cell to start")
                self.update_display()
                return

            # Check if swap is valid
            check_result = check_swap(first_letter, second_letter)
            if check_result != "valid":
                self.status_label.setText(f"Invalid swap: {check_result}")
                self.selected_cell = None
                self.update_display()
                return

            # Perform swap
            new_grid = swap_cells(first_letter, second_letter, self.current)
            if isinstance(new_grid, str):
                self.status_label.setText(f"Swap failed: {new_grid}")
                self.selected_cell = None
                self.update_display()
                return

            # Update game state
            self.current = new_grid
            self.swap_count += 1
            write_log((first_letter, second_letter))

            self.selected_cell = None
            self.status_label.setText(f"Swapped {first_letter} ↔ {second_letter}")
            self.update_display()

    def show_victory(self):
        """Show victory message."""
        message = "🎉 CONGRATULATIONS! 🎉\n\n"
        message += f"You solved the puzzle in {self.swap_count} swaps!\n\n"
        message += "Great job!"

        QMessageBox.information(self, "Victory!", message)
        print_log()

    def show_game_over(self):
        """Show game over message."""
        message = "Game Over!\n\n"
        message += "You've exceeded the maximum of 15 swaps.\n"
        message += "Better luck next time!"

        QMessageBox.warning(self, "Game Over", message)
        print_log()

    def reset_game(self):
        """Reset the game to initial state."""
        reply = QMessageBox.question(
            self,
            "Reset Game",
            "Are you sure you want to reset the game?",
            QMessageBox.Yes | QMessageBox.No,
        )

        if reply == QMessageBox.Yes:
            self.current = self.starter.copy()
            self.swap_count = 0
            self.selected_cell = None

            # Clear log file
            log_path = os.path.join(os.path.dirname(__file__), "log.txt")
            with open(log_path, "w", encoding="utf-8") as fh:
                fh.write("")

            self.status_label.setText("Game reset - Click on two cells to swap them")
            self.update_display()

    def show_moves(self):
        """Show all moves made so far."""
        log_path = os.path.join(os.path.dirname(__file__), "log.txt")

        try:
            if os.path.exists(log_path):
                with open(log_path, "r", encoding="utf-8") as fh:
                    lines = fh.readlines()

                if lines:
                    moves_text = "MOVE LOG\n" + "="*30 + "\n\n"
                    for i, line in enumerate(lines, 1):
                        line = line.strip()
                        if line:
                            moves_text += f"Move {i}: {line}\n"

                    QMessageBox.information(self, "Move History", moves_text)
                else:
                    QMessageBox.information(self, "Move History", "No moves recorded yet.")
            else:
                QMessageBox.information(self, "Move History", "No moves recorded yet.")
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Error reading move log: {e}")

    def quit_game(self):
        """Quit the game."""
        reply = QMessageBox.question(
            self, "Quit", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No
        )

        if reply == QMessageBox.Yes:
            print_log()
            self.close()


if __name__ == "__main__":
    """Main entry point for the GUI application."""
    # Clear log file
    log_path = os.path.join(os.path.dirname(__file__), "log.txt")
    with open(log_path, "w", encoding="utf-8") as fh:
        fh.write("")

    # Create and run GUI
    app = QApplication(sys.argv)
    window = GriddleGUI()
    window.show()
    sys.exit(app.exec())
