# Small architectural intent programs; all geometry remains in shared components.
from hearth import Scene, Box
from hearth.randomness import Scope
from hearth.environment import Terrain, gradient, wave
from hearth.components.building import Blueprint, RoomSpec, adapted
from hearth.components.roofcraft import RoofDesign
from hearth.components.roomlayout import InteriorDesign
from hearth.components.facades import FacadeDesign
from hearth.components.grounds import GardenCourt


def hillside_home(seed):
    rng = Scope(seed).stream('home-layout')
    rooms = [RoomSpec(0, 0, 0, 'living'), RoomSpec(0, 0, 1, 'bedroom'), RoomSpec(1, 0, 0, 'kitchen')]
    if rng.choice((True, False)):
        rooms += [RoomSpec(0, 1, 0, 'library')]
    return Blueprint(tuple(rooms), bay=rng.choice((11, 13)), roof_design=RoofDesign(rng.choice(((1, 2), (1, 1, 2))), end_hips=Scope(seed).choose(((0, 0), (0, 2), (2, 2)), 'roof-ends')), porch_depth=4, balcony=True, chimney=True, facade_design=FacadeDesign(), rail_material='dark_oak', attic_purpose=Scope(seed).choose(('bedroom', 'library'), 'roof-purpose'), interior_design=InteriorDesign())


def gabled_hall(seed):
    rng = Scope(seed).stream('hall-layout')
    rooms = [RoomSpec(0, 0, 0, 'library'), RoomSpec(0, 1, 0, 'living'), RoomSpec(1, 1, 0, 'kitchen')]
    if rng.choice((True, False)):
        rooms += [RoomSpec(0, 1, 1, 'bedroom')]
    if rng.choice((True, False)):
        rooms += [RoomSpec(1, 0, 0, 'workshop')]
    return Blueprint(tuple(rooms), bay=rng.choice((9, 11)), roof_axis=rng.choice(('x', 'z')), roof_design=RoofDesign((1, 2), rng.choice((7, 10)), end_hips=Scope(seed).choose(((0, 0), (0, 2), (2, 2)), 'roof-ends')), porch_depth=5, chimney=True, facade_design=FacadeDesign(), rail_material='dark_oak', attic_purpose=Scope(seed).choose(('bedroom', 'library'), 'roof-purpose'), interior_design=InteriorDesign())


def high_house(seed):
    rng = Scope(seed).stream('vertical-layout')
    rooms = [RoomSpec(0, 0, level, purpose) for level, purpose in enumerate(('living', 'library', 'bedroom'))]
    rooms += [RoomSpec(1, 0, 0, 'kitchen')]
    if rng.choice((True, False)):
        rooms += [RoomSpec(1, 0, 1, 'workshop')]
    if rng.choice((True, False)):
        rooms += [RoomSpec(0, 1, 0, 'storage')]
    return Blueprint(tuple(rooms), bay=rng.choice((9, 11)), roof_design=RoofDesign((2, 1), 8, end_hips=Scope(seed).choose(((0, 0), (1, 3), (3, 3)), 'roof-ends')), porch_depth=4, balcony=rng.choice((True, False)), chimney=True, facade_design=FacadeDesign(), rail_material='dark_oak', attic_purpose=Scope(seed).choose(('bedroom', 'library'), 'roof-purpose'), interior_design=InteriorDesign())


def lodge_scene(design, seed=0, environment_seed=0, field=None, water=None, garden=True):
    """Freeze a general environment, then compose a building and its garden court."""
    design.validate()
    w = (max(r.x for r in design.rooms) + 1) * design.bay
    d = (max(r.z for r in design.rooms) + 1) * design.bay
    domain = Box((-8, -3, -17), (w + 8, 72, d + 9))
    rng = Scope(environment_seed).stream('environment')
    expression = field if field is not None else gradient(rng.choice((-.02, .02, .04)), .012, 2) + wave(.5, .12, .1, rng.random() * 6)
    scene = Scene(seed, domain=domain)
    scene.place('land', Terrain(domain, expression, water))
    scene.finalize()
    scene.compose_choice(adapted('building', design, '/land'))
    if garden:
        scene.place('garden', GardenCourt('/building', '/land', domain))
    return scene.finalize()
