import math
import random

import dice



DUNGEON_WANDERING_MONSTER_LEVEL = {
    #   1  2  3  4  5  6  7  8  9  0  1  2
    1: [1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3],
    2: [1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4],
    3: [1, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5],
    4: [2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 6],
    5: [3, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6],
    6: [4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6],
}

DUNGEON_RANDOM_MONSTERS_BY_LEVEL = {
    1: [
        ("Goblin", "2d4"), ("Kobold", "4d4"), ("Morlock", "1d12"),
        ("Orc", "2d4"), ("Beetle, Fire", "1d8"), ("Centipede, Giant", "2d4"),
        ("Ferret, Giant", "1d8"), ("Rat, Giant", "3d6"), ("Men, Brigand", "2d4"),
        ("Skeleton", "3d4"), ("Stirge", "1d10"), ("NPC Party (Lvl 1)", "1d4+2")
    ],
    2: [
        ("Gnoll", "1d6"), ("Hobgoblin", "1d6"), ("Lizardman", "2d4"),
        ("Troglodyte", "1d8"), ("Bat, Giant", "1d10"),
        ("Fly, Giant Carnivorous", "1d8"), ("Locust, Cavern", "1d10"), 
        ("Snake, Pit Viper", "1d8"), ("Ghoul", "1d6"), ("Men, Berserker", "1d6"),
        ("Zombie", "2d4"), ("NPC Party (Lvl 2)", "1d4+2")
    ],
    3: [
        ("Bugbear", "2d4"), ("Lycanthrope, Werewolf", "1d6"), ("Ogre", "1d6"),
        ("Throghrin", "1d6"), ("Ant, Giant", "2d4"), ("Lizard, Drago", "1d3"),
        ("Scorpion, Giant", "1d6"), ("Wolf, Dire", "1d4"),
        ("Carcass Scavenger", "1d3"), ("Gargoyle", "1d6"), ("Wight", "1d6"),
        ("NPC Party (Lvl 4)", "1d4+2")
    ],
    4: [
        ("Lycanthrope, Werebear", "1d4"), ("Lycanthrope, Weretiger", "1d4"),
        ("Minotaur", "1d6"), ("Boar, Giant", "1d4"), ("Owl Bear", "1d4"),
        ("Phase Tiger", "1d4"), ("Rhagodessa, Giant", "1d4"),
        ("Snake, Giant Python", "1d4"), ("Cockatrice", "1d4"), ("Medusa", "1d3"),
        ("Wraith", "1d4"), ("NPC Party (Lvl 5)", "1d4+2")
    ],
    5: [
        ("Ettin", "1d2"), ("Giant, Hill", "1d4"), ("Giant, Stone", "1d2"),
        ("Troll", "1d8"), ("Ankheg", "1d6"), ("Caecilian", "1d3"),
        ("Basilisk", "1d6"), ("Hell Hound, Greater", "2d4"),
        ("Salamander, Flame", "1d4+1"), ("Spectre", "1d4"), ("Wyvern", "1d2"),
        ("NPC Party (Lvl 8)", "1d4+3")
    ],
    6: [
        ("Cyclops", "1`"), ("Giant, Cloud", "1d2"), ("Purple Worm", "1d2"),
        ("Demon Boar", "1d4"), ("Dragon (20 HD)", "1"), ("Hydra (12 HD)", "1"),
        ("Gorgon", "1d2"), ("Lamia", "1"), ("Remorhaz (15 HD)", "1"),
        ("Skittering Maw", "1"), ("Vampire (9 HD)", "1d4"),
        ("NPC Party (Lvl 14)", "1d4+3")
    ]
}

WILDERNESS_TYPE_BY_ID = {
    1: ["Clear", "Grass", "Scrub"],
    2: ["Woods"],
    3: ["River"],
    4: ["Swamp"],
    5: ["Mountains", "Hills"],
    6: ["Barren", "Desert"],
    7: ["Inhabited"],
    8: ["City"],
    9: ["Ocean"],
    10: ["Jungle"],
}

WILDERNESS_FREQUENCY_BY_TERRAIN = {
    1:  6, # Clear, Grass, Scrub
    2:  5, # Woods
    3:  5, # River
    4:  4, # Swamp
    5:  4, # Mountains, Hills
    6:  4, # Barren, Desert
    7:  6, # Inhabited
    8:  6, # City
    9:  5, # Ocean
    10: 4, # Jungle
}

WILDERNESS_ENCOUNTER_BY_TERRAIN = {
    1:  ["Men", "Flyer", "Humanoid", "Animal", "Animal", "Unusual", "Dragon", "Insect"],
    2:  ["Men", "Flyer", "Humanoid", "Insect", "Unusual", "Animal", "Animal", "Dragon"],
    3:  ["Men", "Flyer", "Humanoid", "Insect", "Swimmer", "Swimmer", "Animal", "Dragon"],
    4:  ["Men", "Flyer", "Humanoid", "Swimmer", "Undead", "Undead", "Insect", "Dragon"],
    5:  ["Men", "Flyer", "Humanoid", "Unusual", "Animal", "Humanoid", "Dragon", "Flyer"],
    6:  ["Men", "Flyer", "Humanoid", "Humanoid", "Animanl", "Dragon", "Undead", "Unusual"],
    7:  ["Men", "Flyer", "Humanoid", "Men", "Men", "Insect", "Animal", "Dragon"],
    8:  ["Men", "Undead", "Humanoid", "Men", "Men", "Men", "Men", "Men", "Men", "Men"],
    9:  ["Men", "Flyer", "Insect", "Insect", "Humanoid", "Animal", "Animal", "Dragon"],
    10: ["Men", "Flyer", "Insect", "Insect", "Humanoid", "Animal", "Animal", "Dragon"],
}

WILDERNESS_ENCOUNTER_SUBTABLES = {
    "Men": {
        "Clear, Grass, Scrub":  ["Brigand", "Noble", "Mage", "Fighter", "Thief", "Cleric", "Nomad", "Thief", "NPC Party", "Merchant", "Berserker", "Venturer"],
        "Woods":  ["Brigand", "Thief", "NPC Party", "Merchant", "Berserker", "Brigand", "Cleric", "Mage", "Fighter", "Thief", "Brigand", "NPC Party"],
        "River":  ["Brigand", "Thief", "NPC Party", "Merchant", "Buccaneer", "Buccaneer", "Cleric", "Mage", "Fighter", "Merchant", "Buccaneer", "NPC Party"],
        "Swamp":  ["Brigand", "Thief", "NPC Party", "NPC Party", "Merchant", "Cleric", "Venturer", "Berserker",  "Fighter", "Mage", "NPC Party", "Thief"],
        "Barrens, Mountains, Hills":  ["Brigand", "Thief", "NPC Party", "Venturer", "Berserker", "NPC Party", "Cleric", "Mage", "Fighter", "Brigand", "NPC Party", "Barbarian"],
        "Desert":  ["Nomad", "Nomad", "NPC Party", "Merchant", "Nomad", "Nomad", "Cleric", "Mage", "Fighter", "Noble", "Nomad", "Nomad"],
        "Inhabited":  ["Thief", "Venturer", "NPC Party", "NPC Party", "Merchant", "Fighter", "Merchant", "Fighter", "Mage", "Cleric", "Cleric", "Noble"],
        "City":  ["Thief", "Venterer", "NPC Party", "NPC Party", "Merchant", "Fighter", "Merchant", "Fighter", "Mage", "Cleric", "Cleric", "Noble"],
        "Ocean":  ["Buccaneer", "Pirate", "Merchant", "NPC Party", "Pirate", "Merchant", "Merchant", "Merchant", "Buccaneer", "Pirate", "Merchant", "Pirate"],
        "Jungle": ["Brigand", "Venturer", "Thief", "NPC Party", "Cleric", "Fighter", "Medium", "Berserker", "Brigand", "Barbarian", "NPC Party", "Brigand"],
    },
    "Humanoid": {
        "Clear, Grass, Scrub":  ["Bugbear", "Elf", "Gnoll", "Goblin", "Halfling", "Hobgoblin", "Kobold", "Ogre", "Orc", "Pixie", "Throghrin", "Troll"],
        "Woods":  ["Bugbear", "Cyclops", "Dryad", "Elf", "Giant, Hill", "Gnoll", "Goblin", "Hobgoblin", "Ogre", "Orc", "Pixie", "Troll"],
        "River":  ["Bugbear", "Elf", "Gnoll", "Hobgoblin", "Lizard Man", "Lizard Man", "Naiad", "Naiad", "Ogre", "Orc", "Sprite", "Troll"],
        "Swamp":  ["Gnoll", "Goblin", "Hobgoblin", "Lizard Man", "Lizard Man", "Lizard Man", "Naiad", "Ogre", "Orc", "Troglodyte", "Troll", "Troll"],
        "Hills, Mountain":  ["Dwarf", "Giant, Cloud", "Giant, Frost", "Giant, Hill", "Giant, Stone", "Giant, Storm", "Goblin", "Kobold", "Ogre", "Orc", "Troglodyte", "Troll"],
        "Barrens":  ["Bugbear", "Giant, Hill", "Goblin", "Gnoll", "Hobgoblin", "Hobgoblin", "Ogre", "Orc", "Orc", "Throghrin", "Troll"],
        "Desert":  ["Bugbear", "Gnoll", "Giant, Fire", "Hobgoblin", "Hobgoblin", "Minotaur", "Ogre", "Ogre", "Orc", "Orc", "Troll", "Troll"],
        "City":  ["Doppelganger", "Dwarf", "Elf", "Gnome", "Halfling", "Pixie", "Sprite", "Werebear", "Wereboar", "Wererat", "Weretiger", "Werewolf"],
        "Inhabited":  ["Doppelganger", "Dwarf", "Elf", "Gnome", "Goblin", "Halfling", "Kobold", "Ogre", "Orc", "Pixie", "Sprite", "Wererat"],
        "Jungle": ["Bugbear", "Cyclops", "Elf", "Giant, Fire", "Giant, Hill", "Gnoll", "Goblin", "Lizard Man", "Ogre", "Orc", "Troglodyte", "Troll"],
    },
    "Animal": {
        "Clear, Grass, Scrub":  ["Herd Animal (Antelope)", "Boar*", "Cat, Lion", "Cat, Panther", "Elephant", "Hawk*", "Horse, Light", "Lizard, Tuatara", "Mule (Donkey)", "Snake, Pit Viper", "Snake, Giant Rattler", "Weasel, Giant"],
        "Woods":  ["Herd Animal (Antelope)", "Bat*", "Bear, Grizzly", "Boar*", "Cat, Panther", "Hawk*", "Owl*", "Snake, Pit Viper", "Spider, Black Widow", "Unicorn", "Wolf", "Wolf, Dire"],
        "River":  ["Herd Animal (Antelope)", "Bear, Black", "Boar*", "Cat, Panther", "Crab, Giant", "Crocodile*", "Leech, Giant", "Piranha, Giant", "Rat*", "Shrew, Giant", "Swan", "Toad, Giant"],
        "Hills":  ["Herd Animal (Antelope)", "Bear, Grizzly", "Boar*", "Cat, Mountain Lion", "Eagle*", "Hawk*", "Horse, Light", "Herd Animal (Sheep)", "Snake, Pit Viper", "Owl*", "Wolf", "Wolf, Dire"],
        "Mountains":  ["Herd Animal (Antelope)", "Bear, Cave", "Cat, Mountain Lion", "Eagle*", "Herd Animal (Goat)", "Hawk*", "Mule (Donkey)", "Baboon, Rock", "Snake, Pit Viper", "Snake, Giant Rattler", "Wolf", "Wolf, Dire"],
        "Barrens":  ["Herd Animal (Antelope)", "Bear, Cave", "Cat, Mountain Lion", "Eagle*", "Goat, Wild", "Hawk*", "Rock Babooon", "Snake, Pit Viper", "Snake, Giant Rattler", "Spider, Crab", "Wolf, Dire", "Vulture"],
        "Desert":  ["Herd Animal (Antelope)", "Herd Animal (Antelope)", "Camel", "Camel", "Cat, Lion", "Hawk*", "Lizard, Gecko", "Lizard, Tuatara", "Snake, Giant Rattler", "Wolf (Wild Dog)", "Wolf, Dire", "Vulture"],
        "Inhabited": ["Herd Animal (Antelope)", "Boar*", "Cat, Panther", "Lizard, Draco", "Lizard, Gecko", "Lizard, Horned", "Monkey", "Shrew, Giant", "Snake, Pit Viper", "Snake, Python", "Snake, Spitting Cobra", "Spider, Crab"],
        "Jungle":  ["Goat", "Boar*", "Dog", "Ferret, Giant", "Hawk*", "Horse, Light", "Mule (Donkey)", "Rat*", "Snake, Pit Viper", "Herd Animal (Sheep)", "Weasel, Giant", "Wolf"],
        "Other":  ["Bear, Cave", "Cat, Sabre-Tooth Tiger", "Crocodile, Giant", "Mastodon", "Pteranodon", "Rhino, Woolly", "Snake, Python", "Stegosaurus", "Titanothere", "Triceratops", "Tyrannosaurus Rex", "Wolf, Dire"],
        "*": "Roll 1d6: 1-4 Normal or Swarm, 5-6 Giant"
    },
    "Flyer": {
        "Barrens":  ["Cockatrice", "Gargoyle", "Griffon", "Harpy", "Hawk, Giant", "Hippogriff", "Lammasu", "Manticore", "Pegasus", "Roc, Small", "Stirge", "Wyvern"],
        "Desert":  ["Chimera", "Cockatrice", "Gargoyle", "Griffon", "Hawk, Giant", "Lammasu", "Manticore", "Pterodactyl", "Roc, Small", "Sphinx", "Wyvern", "Vulture"],
        "Mountains":  ["Swarm, Bat", "Chimera", "Cockatrice", "Gargoyle", "Griffon", "Harpy", "Hawk, Giant", "Hippogriff", "Manticore", "Pegasus", "Roc*", "Wyvern"],
        "Woods":  ["Bat, Giant", "Swarm, Bat", "Cockatrice", "Griffon", "Hawk, Giant", "Hippogriff", "Pegasus", "Owl, Giant", "Pixie", "Roc, Small", "Sprite", "Stirge"],
        "Other":  ["Cockatrice", "Fly, Giant Carnivorous", "Gargoyle", "Griffon", "Hawk, Giant", "Hippogriff", "Bee, Killer Giant", "Pegasus", "Pixie", "Roc, Small", "Sprite", "Stirge"],
        "*": "Roll 1d6: 1-3 Small, 4-5 Large, 6 Giant"
    },
    "Swimmer": {
        "River, Lake":  ["Crab, Giant", "Crocodile", "Crocodile", "Crocodile, Large", "Fish, Catfish", "Fish, Piranha", "Fish, Sturgeon", "Leech, Giant", "Lizard Man", "Merman", "Naiad", "Skittering Maw"],
        "Ocean":  ["Dragon Turtle", "Hydra, Sea", "Merman", "Octopus, Giant", "Sea Dragon", "Sea Serpent", "Shark*", "Shark*", "Skittering Maw", "Snake, Sea", "Squid, Giant", "Whale"],
        "Swamp":  ["Crab, Giant", "Crocodile", "Crocodile, Large", "Crocodile, Giant", "Fish, Catfish", "Insect Swarm", "Insect Swawrm", "Leech, Giant", "Leech, Giant", "Lizard Man", "Lizard Man", "Skittering Maw"],
        "*": "Roll 1d6: 1-2 Bull Shark, 3-4 Mako Shark, 5-6 Great White Shark"
    },
    "Dragon": {
        "Other": ["Basilisk", "Caecilian", "Chimera", "Dragon*", "Dragon*", "Sphinx", "Hydra/Sea Hydra", "Lamia", "Purple Worm", "Snake, Python", "Salamander", "Wyvern"],
        "*": "Always Black in Swamp, Blue in Mountains, Brown in Desert, Green in Woods, Red in Barrens, Sea in Oceans/Rivers/Lake. Otherwise roll 1d10: 1 Black, 2 Blue, 3 Brown, 4 Green, 5 Metallic, 6 Red, 7 Sea, 8 White, 9 Wyrm, 10 Judge’s Choice.",
    },
    "Insect": {
        "Other": ["Beetle, Fire", "Beetle, Giant Bombardier", "Beetle, Tiger", "Carcass Scavenger", "Centipede, Giant", "Ant, Giant", "Fly, Giant Carnivorous", "Killer Bee", "Rhagodessa", "Scorpion, Giant", "Spider, Black Widow", "Spider, Crab"],
    },
    "Undead": {
        "Other": ["Ghoul", "Ghoul", "Mummy", "Mummy", "Skeleton", "Skeleton", "Spectre", "Wight", "Wraith", "Vampire", "Zombie", "Zombie"],
    },
    "Unusual": {
        "Other": ["Basilisk", "Blink Dog", "Centaur", "Gorgon", "Hellhound", "Lycanthrope", "Medusa", "Phase Tiger", "Rust Monster", "Skittering Maw", "Treant", "Ape, White"],
    }
}


def surprise_roll(mod):
    roll = int(dice.roll("1d6 + {}".format(mod)))
    status = "Surprised" if roll < 3 else "Ready"
    return (status, roll)

def reaction_roll(mod, difference):
    roll = int(dice.roll("2d6 + {}".format(mod)))
    roll += difference

    if roll <= 2:
        status = "Hostile, attacks"
    elif roll >= 3 and roll <= 5:
        status = "Unfriendly, may attack"
    elif roll >= 6 and roll <= 8:
        status = "Neutral, uncertain"
    elif roll >= 9 and roll <= 11:
        status = "Indifferent, uninterested"
    elif roll >= 12:
        status = "Friendly, helpful"

    return (status, roll)

def check_encounter(mod=0, throw=6):
    roll = int(dice.roll("1d6 + {}".format(mod)))
    return ((roll >= throw), roll)

def generate_dungeon_monster(check_mod, dungeon_level, reaction_mod, surprise_mod):
    check = check_encounter(check_mod)
    if not check[0]:
        return {"check": False, "check_roll": check[1]}

    if not dungeon_level in DUNGEON_WANDERING_MONSTER_LEVEL:
        return None

    monster_table = random.choice(DUNGEON_WANDERING_MONSTER_LEVEL[dungeon_level])
    encounter = random.choice(DUNGEON_RANDOM_MONSTERS_BY_LEVEL[monster_table])

    difference = monster_table - dungeon_level

    quantity = int(dice.roll(encounter[1]))
    adjusted = quantity
    for _ in range(abs(difference)):
        adjusted = adjusted + (adjusted * 0.5) if difference > 0 else adjusted - (adjusted * 0.5)
    adjusted = math.floor(adjusted) if adjusted > 1 else 1

    distance = int(dice.roll("2d6")) * 10
    surprise = surprise_roll(surprise_mod)
    reaction = reaction_roll(reaction_mod, difference)

    return {
        "dungeon_level": dungeon_level,
        "monster_table": monster_table,
        "entity": encounter[0],
        "quantity": adjusted,
        "initial": quantity,
        "roll": encounter[1],
        "adjustment": difference,
        "distance": distance,
        "surprise": surprise,
        "reaction": reaction,
        "check": True,
        "check_roll": check[1]
    }

def generate_wilderness_monster(check_mod, terrain_type, reaction_mod, surprise_mod):
    check_throw = WILDERNESS_FREQUENCY_BY_TERRAIN[terrain_type]
    check = check_encounter(check_mod, check_throw)
    if not check[0]:
        return {"check": False, "check_roll": check[1]}

    encounter_type_roll = int(dice.roll("1d8"))
    encounter_type = WILDERNESS_ENCOUNTER_BY_TERRAIN[terrain_type][encounter_type_roll - 1]

    subtable  = WILDERNESS_ENCOUNTER_SUBTABLES[encounter_type]
    terrain_type_labels = WILDERNESS_TYPE_BY_ID[terrain_type]

    endtable = None
    for k in subtable.keys():
        for l in terrain_type_labels:
            if l in k:
                endtable = subtable[k]
    if endtable == None and "Other" in subtable:
        endtable = subtable["Other"]

    entity_roll = int(dice.roll("1d12"))
    entity = endtable[entity_roll - 1]

    surprise = surprise_roll(surprise_mod)
    reaction = reaction_roll(reaction_mod, 0)

    return {
        "terrain_type": ', '.join(terrain_type_labels),
        "monster_table": encounter_type,
        "entity": entity,
        "surprise": surprise,
        "reaction": reaction,
        "check": True,
        "check_roll": check[1]
    }
