# Depth and joinery fitted to public wall interfaces without replacing openings.
from dataclasses import dataclass
from hearth import Box, ContractError
from hearth.kernel import Capability, Contract, Plan, Rule
from hearth.blocks import name_of, log, stairs, slab


@dataclass(frozen=True)
class FacadeRelief:
    """Fit external beams and brackets around an already installed facade."""
    width: int
    height: int = 5
    access: bool = False

    def capability(self):
        return Capability('facade.joinery', ('decoration', 'timber-frame'), assumptions=('wall-installation host',), adaptations=('preserve shutters and other occupied facade cells',), guarantees=('one-cell projection',))

    def negotiate(self, ctx, parameters):
        if len(ctx.bindings) != 1 or ctx.view.port(ctx.bindings[0].host, ctx.bindings[0].port).kind != 'wall-installation':
            raise ContractError('joinery-host', ctx.path)
        points = {}
        for x in range(self.width):
            points[(x, self.height - 1, -1)] = log('spruce', 'x')
            if not (self.access and abs(x - self.width // 2) <= 1):
                points[(x, -1, -1)] = slab('dark_oak', 'top')
        for x in (0, self.width - 1):
            for y in range(self.height - 1):
                points[(x, y, -1)] = log('stripped_spruce')
        for x, direction in ((1, 'east'), (self.width - 2, 'west')):
            points[(x, self.height - 2, -1)] = stairs('spruce', direction, 'top')
        available = [(q, s) for q, s in sorted(points.items()) if name_of(ctx.state(q)) == 'air']
        return Contract(Box((0, -1, -1), (self.width - 1, self.height - 1, 0)), rules=(Rule('support', ((0, self.height - 1, 0), (self.width - 1, self.height - 1, 0))),), decisions={'members': available, 'preserved_occupied_cells': len(points) - len(available)})

    def realize(self, ctx, contract):
        p = Plan()
        for q, block in contract.decisions['members']:
            p.block(q, block, 'joinery')
        return p
