import random
from textual.app import ComposeResult
from textual.screen import Screen
from textual.widgets import Header, Footer, Button, Label, Input, RichLog, Static
from textual.containers import Grid, Horizontal, Vertical
from textual import on

# 1. Tic-Tac-Toe Screen
class TicTacToeScreen(Screen):
    CSS = """
    #ttt_grid {
        grid-size: 3;
        grid-gutter: 1 2;
        padding: 2;
        align: center middle;
        width: 30;
        height: 15;
    }
    .ttt_cell {
        width: 100%;
        height: 100%;
        content-align: center middle;
    }
    .container {
        align: center middle;
    }
    """
    def __init__(self):
        super().__init__()
        self.board = [" "]*9
        self.game_over = False

    def compose(self) -> ComposeResult:
        yield Header()
        with Vertical(classes="container"):
            yield Label("Tic-Tac-Toe vs Ana AI! Your turn (X).", id="ttt_status")
            with Grid(id="ttt_grid"):
                for i in range(9):
                    yield Button(" ", id=f"cell_{i}", classes="ttt_cell")
            yield Button("Back to Games", id="btn_back", variant="error")
        yield Footer()

    @on(Button.Pressed)
    def handle_click(self, event: Button.Pressed):
        btn_id = event.button.id
        if btn_id == "btn_back":
            self.app.pop_screen()
            return
            
        if self.game_over or not btn_id.startswith("cell_"):
            return
            
        idx = int(btn_id.split("_")[1])
        if self.board[idx] != " ":
            return
            
        self.board[idx] = "X"
        event.button.label = "X"
        event.button.variant = "primary"
        event.button.disabled = True
        
        if self.check_win():
            self.query_one("#ttt_status", Label).update("[bold green]You win![/bold green]")
            self.game_over = True
        elif " " not in self.board:
            self.query_one("#ttt_status", Label).update("[bold yellow]It's a draw![/bold yellow]")
            self.game_over = True
        else:
            self.query_one("#ttt_status", Label).update("[bold magenta]Ana AI is thinking...[/bold magenta]")
            self.set_timer(0.4, self.ana_move)

    def ana_move(self):
        if self.game_over: return
        
        best_score = -float('inf')
        best_move = None
        for i in range(9):
            if self.board[i] == " ":
                self.board[i] = "O"
                score = self.minimax(self.board, 0, False)
                self.board[i] = " "
                if score > best_score:
                    best_score = score
                    best_move = i
                    
        if best_move is not None:
            self.board[best_move] = "O"
            btn = self.query_one(f"#cell_{best_move}", Button)
            btn.label = "O"
            btn.variant = "warning"
            btn.disabled = True
            
            if self.check_win():
                self.query_one("#ttt_status", Label).update("[bold red]Ana AI wins![/bold red]")
                self.game_over = True
            elif " " not in self.board:
                self.query_one("#ttt_status", Label).update("[bold yellow]It's a draw![/bold yellow]")
                self.game_over = True
            else:
                self.query_one("#ttt_status", Label).update("Your turn (X).")

    def minimax(self, board, depth, is_maximizing):
        if self._check_win_for(board, "O"): return 10 - depth
        if self._check_win_for(board, "X"): return -10 + depth
        if " " not in board: return 0
        
        if is_maximizing:
            best_score = -float('inf')
            for i in range(9):
                if board[i] == " ":
                    board[i] = "O"
                    score = self.minimax(board, depth + 1, False)
                    board[i] = " "
                    best_score = max(score, best_score)
            return best_score
        else:
            best_score = float('inf')
            for i in range(9):
                if board[i] == " ":
                    board[i] = "X"
                    score = self.minimax(board, depth + 1, True)
                    board[i] = " "
                    best_score = min(score, best_score)
            return best_score
            
    def _check_win_for(self, board, player):
        win_states = [(0,1,2), (3,4,5), (6,7,8), (0,3,6), (1,4,7), (2,5,8), (0,4,8), (2,4,6)]
        for a, b, c in win_states:
            if board[a] == board[b] == board[c] == player:
                return True
        return False

    def check_win(self):
        win_states = [(0,1,2), (3,4,5), (6,7,8), (0,3,6), (1,4,7), (2,5,8), (0,4,8), (2,4,6)]
        for a, b, c in win_states:
            if self.board[a] == self.board[b] == self.board[c] != " ":
                return True
        return False

# 2. Number Guesser Screen
class NumberGuesserScreen(Screen):
    CSS = """
    .container {
        align: center middle;
        padding: 2;
        width: 100%;
        height: 100%;
    }
    #guess_log {
        height: 1fr;
        margin: 1 0;
        border: solid cyan;
    }
    """
    def __init__(self):
        super().__init__()
        self.target = random.randint(1, 100)
        self.attempts = 0

    def compose(self) -> ComposeResult:
        yield Header()
        with Vertical(classes="container"):
            yield Label("[bold cyan]I'm thinking of a number between 1 and 100.[/bold cyan]", id="guess_status")
            yield Input(placeholder="Enter your guess...", id="guess_input", type="integer")
            yield RichLog(id="guess_log", wrap=True)
            yield Button("Back to Games", id="btn_back", variant="error")
        yield Footer()

    @on(Button.Pressed, "#btn_back")
    def go_back(self):
        self.app.pop_screen()

    @on(Input.Submitted, "#guess_input")
    def handle_guess(self, event: Input.Submitted):
        try:
            guess = int(event.value)
        except ValueError:
            return
            
        self.attempts += 1
        log = self.query_one("#guess_log", RichLog)
        
        if guess < self.target:
            log.write(f"[yellow]{guess}[/yellow] is too low.")
        elif guess > self.target:
            log.write(f"[yellow]{guess}[/yellow] is too high.")
        else:
            log.write(f"[bold green]Correct![/bold green] You guessed it in {self.attempts} tries.")
            self.query_one("#guess_status", Label).update(f"[bold green]YOU WON IN {self.attempts} ATTEMPTS![/bold green]")
            self.query_one("#guess_input", Input).disabled = True
            
        event.input.value = ""

# 3. Trivia Screen
class TriviaScreen(Screen):
    CSS = """
    .container {
        align: center middle;
        padding: 2;
        width: 100%;
        height: 100%;
    }
    #trivia_q {
        margin-bottom: 2;
        text-align: center;
        text-style: bold;
    }
    .ans_btn {
        width: 100%;
        margin-bottom: 1;
    }
    """
    def __init__(self):
        super().__init__()
        self.questions = [
            ("What is the capital of France?", ["London", "Berlin", "Paris", "Madrid"], 2),
            ("Which planet is known as the Red Planet?", ["Earth", "Mars", "Jupiter", "Venus"], 1),
            ("What does HTTP stand for?", ["HyperText Transfer Protocol", "HyperText Transmission Process", "Hyperlink Transfer Technology", "Hyperlink Text Protocol"], 0),
            ("In Python, what keyword defines a function?", ["func", "def", "lambda", "function"], 1),
        ]
        self.current_q = 0
        self.score = 0

    def compose(self) -> ComposeResult:
        yield Header()
        with Vertical(classes="container"):
            yield Label(self.questions[0][0], id="trivia_q")
            for i in range(4):
                yield Button(self.questions[0][1][i], id=f"ans_{i}", classes="ans_btn")
            yield Label("\nScore: 0", id="trivia_score")
            yield Button("Back to Games", id="btn_back", variant="error")
        yield Footer()

    @on(Button.Pressed)
    def handle_answer(self, event: Button.Pressed):
        btn_id = event.button.id
        if btn_id == "btn_back":
            self.app.pop_screen()
            return

        if not btn_id.startswith("ans_"):
            return

        idx = int(btn_id.split("_")[1])
        correct_idx = self.questions[self.current_q][2]
        
        if idx == correct_idx:
            self.score += 1
            self.app.notify("Correct!", severity="information")
        else:
            self.app.notify("Incorrect!", severity="error")

        self.current_q += 1
        if self.current_q < len(self.questions):
            self.query_one("#trivia_q", Label).update(self.questions[self.current_q][0])
            for i in range(4):
                self.query_one(f"#ans_{i}", Button).label = self.questions[self.current_q][1][i]
            self.query_one("#trivia_score", Label).update(f"\nScore: {self.score}")
        else:
            self.query_one("#trivia_q", Label).update(f"[bold green]Game Over! Final Score: {self.score}/{len(self.questions)}[/bold green]")
            for i in range(4):
                self.query_one(f"#ans_{i}", Button).disabled = True

# 4. Snake Screen
class SnakeScreen(Screen):
    CSS = """
    #snake_board {
        text-align: center;
        width: 100%;
        height: 1fr;
        padding: 1;
    }
    .container {
        align: center middle;
    }
    """
    BINDINGS = [
        ("w", "up", "Up"),
        ("s", "down", "Down"),
        ("a", "left", "Left"),
        ("d", "right", "Right"),
    ]
    
    def __init__(self):
        super().__init__()
        self.width = 30
        self.height = 15
        self.snake = [(10, 5), (9, 5), (8, 5)]
        self.dir = (1, 0)
        self.food = (20, 10)
        self.game_timer = None

    def compose(self) -> ComposeResult:
        yield Header()
        with Vertical(classes="container"):
            yield Label("[bold cyan]Use W A S D to move. Welcome to Snake![/bold cyan]", id="snake_score")
            yield Static("", id="snake_board")
            yield Button("Back to Games", id="btn_back", variant="error")
        yield Footer()

    def on_mount(self):
        self.game_timer = self.set_interval(0.15, self.game_loop)
        self.draw_board()

    def draw_board(self):
        board = ""
        for y in range(self.height):
            for x in range(self.width):
                if (x, y) == self.food:
                    board += "[red]🍎[/red]"
                elif (x, y) in self.snake:
                    board += "[green]🟩[/green]"
                else:
                    board += "[dim]· [/dim]"
            board += "\n"
        try:
            self.query_one("#snake_board", Static).update(board)
            self.query_one("#snake_score", Label).update(f"Score: {len(self.snake)}")
        except:
            pass

    def game_loop(self):
        head_x, head_y = self.snake[0]
        new_head = (head_x + self.dir[0], head_y + self.dir[1])
        
        if new_head[0] < 0 or new_head[0] >= self.width or new_head[1] < 0 or new_head[1] >= self.height:
            self.game_timer.pause()
            self.query_one("#snake_score", Label).update(f"[bold red]GAME OVER![/bold red] Score: {len(self.snake)}")
            return
            
        if new_head in self.snake:
            self.game_timer.pause()
            self.query_one("#snake_score", Label).update(f"[bold red]GAME OVER![/bold red] Score: {len(self.snake)}")
            return
            
        self.snake.insert(0, new_head)
        
        if new_head == self.food:
            self.food = (random.randint(0, self.width-1), random.randint(0, self.height-1))
        else:
            self.snake.pop()
            
        self.draw_board()

    def action_up(self):
        if self.dir != (0, 1):
            self.dir = (0, -1)
    def action_down(self):
        if self.dir != (0, -1):
            self.dir = (0, 1)
    def action_left(self):
        if self.dir != (1, 0):
            self.dir = (-1, 0)
    def action_right(self):
        if self.dir != (-1, 0):
            self.dir = (1, 0)
            
    @on(Button.Pressed, "#btn_back")
    def go_back(self):
        if self.game_timer:
            self.game_timer.stop()
        self.app.pop_screen()

# 5. Doge Runner Screen
class DogeRunnerScreen(Screen):
    CSS = """
    #runner_board {
        text-align: center;
        width: 100%;
        height: 1fr;
        padding: 1;
    }
    .container {
        align: center middle;
    }
    """
    BINDINGS = [
        ("space,w,up", "jump", "Jump"),
    ]
    
    def __init__(self):
        super().__init__()
        self.width = 40
        self.ground_y = 5
        self.doge_pos = 0
        self.doge_velocity = 0
        self.obstacles = []
        self.score = 0
        self.game_timer = None
        self.frames = 0
        self.game_over = False

    def compose(self) -> ComposeResult:
        yield Header()
        with Vertical(classes="container"):
            yield Label("[bold cyan]Press SPACE or W or UP to Jump. Doge Runner by Ana.[/bold cyan]", id="runner_score")
            yield Static("", id="runner_board")
            yield Button("Back to Games", id="btn_back", variant="error")
        yield Footer()

    def on_mount(self):
        self.game_timer = self.set_interval(0.1, self.game_loop)
        self.draw_board()

    def draw_board(self):
        board_lines = [""] * 6
        doge_y = self.ground_y - int(self.doge_pos)
        
        for y in range(6):
            line = ""
            for x in range(self.width):
                char = "[dim] [/dim]"
                has_obstacle = False
                for obs_x in self.obstacles:
                    if x == obs_x and y >= 4:
                        char = "[green]🌵[/green]" 
                        has_obstacle = True
                        break
                        
                if not has_obstacle:
                    if x == 5 and y == doge_y:
                        char = "[yellow]🐕[/yellow]"
                    elif y == 5:
                        char = "[dim]_[/dim]"
                line += char
            board_lines[y] = line
            
        board = "\n".join(board_lines)
        if self.game_over:
            board = "\n" + "[bold red]       * BONK * GAME OVER        [/bold red]\n" + board
            
        try:
            self.query_one("#runner_board", Static).update(board)
            if self.game_over:
                self.query_one("#runner_score", Label).update(f"[bold red]GAME OVER![/bold red] Final Score: {self.score}")
            else:
                self.query_one("#runner_score", Label).update(f"Score: {self.score}")
        except:
            pass

    def game_loop(self):
        if self.game_over:
            return
            
        self.frames += 1
        
        if self.doge_pos > 0 or self.doge_velocity > 0:
            self.doge_pos += self.doge_velocity
            self.doge_velocity -= 0.5
            
            if self.doge_pos <= 0:
                self.doge_pos = 0
                self.doge_velocity = 0
                
        new_obs = []
        for obs in self.obstacles:
            if obs > 0:
                new_obs.append(obs - 1)
            else:
                self.score += 10
        self.obstacles = new_obs
        
        if self.frames % 20 == 0:
            if random.random() > 0.4:
                self.obstacles.append(self.width - 1)
                
        doge_hitbox_y = self.ground_y - int(self.doge_pos)
        for obs in self.obstacles:
            if obs == 5 and doge_hitbox_y >= 4:
                self.game_over = True
                self.game_timer.pause()
                break
                
        self.draw_board()

    def action_jump(self):
        if self.doge_pos == 0 and not self.game_over:
            self.doge_velocity = 1.5
            
    @on(Button.Pressed, "#btn_back")
    def go_back(self):
        if self.game_timer:
            self.game_timer.stop()
        self.app.pop_screen()
