# Small continuous bearing courses spanning explicitly measured support columns.
from dataclasses import dataclass
from hearth import Box, ContractError
from hearth.kernel import Capability, Contract, Domain, Rule, Plan
from hearth.blocks import state_of, solid


@dataclass(frozen=True)
class BearingCourse:
    width: int
    depth: int
    span: int = 2

    def capability(self):
        return Capability('adapter.bearing-course', ('siteworks', 'support'), inputs={'width': Domain(1, 7), 'depth': Domain(1, 7), 'span': Domain(0, 3)}, assumptions=('actual support beneath a bounded plate',), guarantees=('continuous bearing surface', 'bounded taxicab span to actual supports'))

    def negotiate(self, ctx, parameters):
        cells = tuple((x, 0, z) for x in range(self.width) for z in range(self.depth))
        anchors = tuple((x, -1, z) for x, _, z in cells if solid(ctx.state((x, -1, z))))
        if not anchors or any(min(abs(x - a) + abs(z - b) for a, _, b in anchors) > self.span for x, _, z in cells):
            raise ContractError('bearing-span', ctx.path, ctx.frame.origin, f'Need support within {self.span} cells of every bearing cell')
        missing = tuple(p for p in cells if not solid(ctx.state(p)))
        return Contract(Box((0, -1, 0), (self.width - 1, 0, self.depth - 1)), rules=(Rule('support', cells + anchors),), decisions={'anchors': anchors, 'fill_cells': missing, 'fill': len(missing), 'span': self.span})

    def realize(self, ctx, contract):
        p = Plan()
        for q in contract.decisions['fill_cells']:
            p.block(q, state_of('stone_bricks'), 'bearing-course')
        return p
