# Lightweight graph clients using frozen generic fields and interchangeable public buildings.
from hearth import Scene, Box, Frame
from hearth.randomness import Scope
from hearth.environment import Terrain, gradient, wave, radial
from hearth.components.building import Blueprint, RoomSpec, Building
from hearth.persistence import semantic_digest
from .geometry import Polygon, Polyline
from .halls import Pavilion
from .graphs import Campus, Vertex, Edge

DOMAIN = Box((-18, -4, -18), (95, 70, 95))


def frozen_site(environment_seed=0, domain=DOMAIN):
    rng = Scope(environment_seed).stream('environment')
    field = gradient(rng.choice((-.012, 0, .012)), rng.choice((-.009, .009)), 5) + wave(.5, .07, .09, rng.random() * 6) + radial(30, 31, 24, -3.8)
    scene = Scene(environment_seed, domain=domain)
    scene.place('land', Terrain(domain, field, water_level=3, edit_limit=2500))
    return scene.finalize()


def branching_campus(seed=0):
    rng = Scope(seed).stream('branching-graph')
    hub = Pavilion(Polygon.chamfered(17, 17, 4), '/land', 'library', ('north', 'east', 'south', 'west'), height=6, lantern=True)
    west = Pavilion(Polygon.chamfered(13, rng.choice((13, 17)), 2), '/land', 'workshop', ('north', 'south'), height=5)
    east = Pavilion(Polygon.chamfered(rng.choice((13, 17)), 13, 2), '/land', 'kitchen', ('west', 'south'), height=rng.choice((5, 6)))
    rooms = [RoomSpec(0, 0, 0, 'living'), RoomSpec(0, 0, 1, 'bedroom')]
    if rng.choice((False, True)):
        rooms.append(RoomSpec(0, 1, 0, 'storage'))
    lodge = Building(Blueprint(tuple(rooms), bay=9, porch=True), '/land')
    vertices = [Vertex('hall', hub, Frame((23, 0, 23))), Vertex('workshop', west, Frame((0, 0, 0))), Vertex('kitchen', east, Frame((51, 0, 0))), Vertex('lodge', lodge, Frame((48, 0, 51)))]
    edges = [Edge('hall', 'north', 'workshop', 'south', covered=True), Edge('hall', 'east', 'kitchen', 'west', rise=rng.choice((0, 1))), Edge('hall', 'south', 'lodge', 'street', covered=True)]
    if rng.choice((False, True)):
        vertices.append(Vertex('archive', Pavilion(Polygon.chamfered(13, 13, 2), '/land', 'library', ('east',)), Frame((0, 0, 51))))
        edges.append(Edge('hall', 'west', 'archive', 'east', rise=1))
    boundary = Polyline.bezier(((-12, 0), (-30, 120), (115, 120), (84, 0)))
    return Campus(tuple(vertices), tuple(edges), '/land', DOMAIN, boundary)


def perimeter_cluster(seed=0):
    rng = Scope(seed).stream('perimeter-graph')
    widths = (rng.choice((17, 21, 25)), rng.choice((13, 17)), rng.choice((13, 17)))
    market = Pavilion(Polygon.chamfered(widths[0], 13, 2), '/land', 'workshop', ('north', 'east', 'south'), height=5, roof_run=3)
    reading = Pavilion(Polygon.chamfered(widths[1], 17, 3), '/land', 'library', ('north', 'south'), height=6, lantern=rng.choice((True, False)))
    dining = Pavilion(Polygon.chamfered(widths[2], 13, 2), '/land', 'living', ('east', 'west'), height=5)
    vertices = (Vertex('market', market, Frame((0, 0, 0))), Vertex('reading', reading, Frame((50, 0, 10))), Vertex('dining', dining, Frame((20, 0, 57))))
    edges = (Edge('market', 'east', 'reading', 'north', via=((40, -5),), covered=False, rise=1), Edge('reading', 'south', 'dining', 'east', covered=True), Edge('dining', 'west', 'market', 'south', via=((9, 42),), rise=rng.choice((0, 1))))
    boundary = Polyline.bezier(((-12, 0), (-30, 120), (115, 120), (84, 0)))
    return Campus(vertices, edges, '/land', DOMAIN, boundary)


def extension_scene(program=branching_campus, seed=0, environment_seed=0):
    environment = frozen_site(environment_seed)
    original = semantic_digest(environment)
    scene = environment.fork(seed=seed)
    scene.place('campus', program(seed))
    scene.finalize()
    if semantic_digest(environment) != original:
        raise AssertionError('Frozen input mutated')
    return scene
