# Accessible platforms with measured supports and oriented edge ports.
from dataclasses import dataclass
from hearth import Box, Frame, Binding, ContractError
from hearth.kernel import Capability, Contract, Plan, Child, Port, Rule, Domain
from hearth.blocks import state_of
from hearth.adapters.site import Foundation, SiteLimits, survey
from .geometry import Polygon, bounds2
from .circulation import Surface

DIRECTIONS = {'north': (0, -1, 0), 'east': (1, 0, 1), 'south': (0, 1, 2), 'west': (-1, 0, 3)}


def edge_frames(width, depth, height):
    return {'north': Frame((width // 2, height, 0), 0), 'east': Frame((width - 1, height, depth // 2), 1), 'south': Frame((width // 2, height, depth - 1), 2), 'west': Frame((0, height, depth // 2), 3)}


@dataclass(frozen=True)
class Platform:
    terrain: str
    width: int = 9
    depth: int = 9
    freeboard: int = 1

    def capability(self):
        return Capability('extension.platform', ('platform', 'composite', 'access'), offers=('access',), inputs={'width': Domain(5, 27), 'depth': Domain(5, 27), 'freeboard': Domain(1, 3)})

    def negotiate(self, ctx, parameters):
        footprint = tuple((x, z) for x in range(self.width) for z in range(self.depth))
        samples = survey(ctx, footprint)
        y = samples['floor'] + self.freeboard - 1
        region = bounds2(footprint, min(v[0] for v in samples['samples'].values()) - 1, y + 3)
        ports = tuple(Port(k, 'access', f, f.box(Box((-2, -1, 0), (2, 1, 0))), 8) for k, f in edge_frames(self.width, self.depth, y + 1).items())
        return Contract(region, ports=ports, decisions={'floor': y, 'footprint': footprint, 'strategy': samples['strategy']}, rules=(Rule('route', tuple(f.frame.origin for f in ports), region, phase='complete'),))

    def realize(self, ctx, contract):
        d = contract.decisions
        p = Plan(children=[Child('foundation', Foundation(tuple(d['footprint']), d['floor'], d['strategy']), bindings=(Binding(self.terrain, 'construction', 'fill'),)), Child('deck', Surface(tuple((x, d['floor'], z) for x, z in d['footprint']), role='platform'))])
        return p
