import curses
import random
import time
import math

# ---------- GLOBAL SETTINGS ----------
WORLD_WIDTH = 150
WORLD_HEIGHT = 50
SCREEN_WIDTH = 30
SCREEN_HEIGHT = 15

# Block symbols
AIR         = ' '
GRASS       = 'G'
DIRT        = 'D'
STONE       = 'S'
WOOD        = 'W'
LEAF        = 'L'
OBSIDIAN    = 'O'
FURNACE_BLK = 'F'

# Colors (if terminal supports)
# (You can later add color attributes with curses.init_pair)

# ---------- PLAYER & ENEMY CLASSES ----------

# The player’s displayed symbol will change based on orientation.
# We map an angle (in degrees) to one of four characters.
def get_direction_symbol(angle):
    # Normalize angle to [0,360)
    angle = angle % 360
    if angle < 45 or angle >= 315:
        return ">"  # facing right
    elif angle < 135:
        return "^"  # facing up
    elif angle < 225:
        return "<"  # facing left
    else:
        return "v"  # facing down

class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.health = 100
        self.inventory = {"wood": 0, "cobblestone": 0}  # expand as needed
        self.orientation = 0  # angle in degrees, default 0 (right)
player = Player(WORLD_WIDTH // 2, WORLD_HEIGHT // 2)

# Define enemy types in Minecraft style.
# Each enemy is a dict with x, y, health and a symbol.
enemy_types = [
    {"type": "zombie",   "symbol": "Z", "health": 20},
    {"type": "skeleton", "symbol": "S", "health": 15},
    {"type": "creeper",  "symbol": "C", "health": 10},
    {"type": "enderman", "symbol": "E", "health": 25}
]
enemies = []  # list of enemy dictionaries

# ---------- WORLD GENERATION ----------
def generate_world():
    world = [[AIR for _ in range(WORLD_WIDTH)] for _ in range(WORLD_HEIGHT)]
    ground_level = WORLD_HEIGHT - 10
    for y in range(WORLD_HEIGHT):
        for x in range(WORLD_WIDTH):
            if y < ground_level - 2:
                world[y][x] = AIR
            elif y < ground_level:
                world[y][x] = DIRT
            elif y == ground_level:
                world[y][x] = GRASS
            else:
                world[y][x] = STONE
    # Build some trees in the “safe” starter area (for x roughly less than 50)
    for _ in range(10):
        tx = random.randint(5, 50)
        ty = ground_level - 1
        # Tree trunk (wood)
        for h in range(3):
            if ty - h >= 0:
                world[ty - h][tx] = WOOD
        # Leaves around the top
        for dx in range(-1, 2):
            for dy in range(-2, 1):
                if 0 <= tx + dx < WORLD_WIDTH and 0 <= ty - 3 + dy < WORLD_HEIGHT:
                    if random.random() < 0.6:
                        world[ty - 3 + dy][tx + dx] = LEAF
    return world

world = generate_world()

# ---------- DRAWING FUNCTION WITH CAMERA ----------
def draw_game(stdscr):
    stdscr.clear()
    # Compute camera offset: center the viewport around the player
    cam_x = max(0, min(player.x - SCREEN_WIDTH // 2, WORLD_WIDTH - SCREEN_WIDTH))
    cam_y = max(0, min(player.y - SCREEN_HEIGHT // 2, WORLD_HEIGHT - SCREEN_HEIGHT))
    
    # Draw the world (each block)
    for y in range(SCREEN_HEIGHT):
        for x in range(SCREEN_WIDTH):
            ch = world[cam_y + y][cam_x + x]
            stdscr.addch(y, x, ch)
    # Draw enemies if they are visible
    for enemy in enemies:
        ex, ey = enemy["x"], enemy["y"]
        if cam_x <= ex < cam_x + SCREEN_WIDTH and cam_y <= ey < cam_y + SCREEN_HEIGHT:
            stdscr.addch(ey - cam_y, ex - cam_x, enemy["symbol"])
    # Draw the player using an orientation–dependent symbol
    player_sym = get_direction_symbol(player.orientation)
    if cam_x <= player.x < cam_x + SCREEN_WIDTH and cam_y <= player.y < cam_y + SCREEN_HEIGHT:
        stdscr.addch(player.y - cam_y, player.x - cam_x, player_sym, curses.A_BOLD)
    # Display status info below the viewport
    status = "Health: {}   Pos: ({}, {})".format(player.health, player.x, player.y)
    stdscr.addstr(SCREEN_HEIGHT, 0, status)
    inv_str = "Inventory: " + str(player.inventory)
    stdscr.addstr(SCREEN_HEIGHT + 1, 0, inv_str)
    prompt = "WASD: move, Mouse: aim, I: inventory, Q: quit"
    stdscr.addstr(SCREEN_HEIGHT + 2, 0, prompt)
    stdscr.refresh()

# ---------- PLAYER MOVEMENT & GRAVITY ----------
def update_player_position(key):
    # Move the player with WASD
    if key == ord('w'):
        if player.y > 0 and world[player.y - 1][player.x] == AIR:
            player.y -= 1
    elif key == ord('s'):
        if player.y < WORLD_HEIGHT - 1 and world[player.y + 1][player.x] == AIR:
            player.y += 1
    elif key == ord('a'):
        if player.x > 0 and world[player.y][player.x - 1] == AIR:
            player.x -= 1
    elif key == ord('d'):
        if player.x < WORLD_WIDTH - 1 and world[player.y][player.x + 1] == AIR:
            player.x += 1
    # Simple gravity: if below is AIR, fall down
    if player.y < WORLD_HEIGHT - 1 and world[player.y + 1][player.x] == AIR:
        player.y += 1

# ---------- ENEMY SPAWN &