# Purpose-specific interior stations with explicit, protected interaction aprons.
from dataclasses import dataclass
from hearth import Box, Frame, ContractError
from hearth.kernel import Capability, Contract, Domain, Port, Rule, Plan
from hearth.blocks import state_of, slab, stairs
from .furnishing import supplies


@dataclass(frozen=True)
class DomesticSuite:
    """A compact room station substitutable through its interaction interface."""
    purpose: str
    width: int = 3

    def capability(self):
        return Capability('furnishing.suite.' + self.purpose, ('furniture', 'station'),
                          inputs={'width': Domain(choices=(2, 3)), 'purpose': Domain(choices=('gathering', 'study', 'cooking', 'craft', 'cabinet'))},
                          offers=('interaction',), guarantees=('supported station', 'two-block interaction apron', 'actual function'))

    def negotiate(self, ctx, parameters):
        if self.width not in (2, 3) or self.purpose not in ('gathering', 'study', 'cooking', 'craft', 'cabinet'):
            raise ContractError('domestic-suite-domain', ctx.path)
        apron = Box((0, 0, 2), (self.width - 1, 1, 2))
        area = Box((0, 0, 0), (self.width - 1, 2, 2))
        function = {'gathering': [['dark_oak_stairs'], ['birch_pressure_plate']], 'study': [['bookshelf'], ['lectern']],
                    'cooking': [['smoker'], ['water_cauldron']], 'craft': [['crafting_table'], ['anvil']], 'cabinet': [['barrel']]}
        return Contract(area, ports=(Port('use', 'interaction', Frame((0, 0, 2)), apron, 4),),
                        rules=(Rule('support', tuple((x, -1, z) for x in range(self.width) for z in range(3))),
                               Rule('clear', tuple(apron.cells())), Rule('furnishing', box=area, data={'groups': function[self.purpose]}, phase='complete')),
                        decisions={'purpose': self.purpose, 'width': self.width}, atomic_object=True)

    def realize(self, ctx, contract):
        p, w = Plan(), self.width
        barrel = state_of('barrel', facing='south', open='false')
        if self.purpose == 'gathering':
            for x in range(w):
                p.block((x, 0, 0), stairs('dark_oak', 'north'), 'settee')
                if x != w // 2:
                    p.block((x, 0, 1), state_of('yellow_carpet'), 'hearth-rug')
            p.block((w // 2, 0, 1), state_of('dark_oak_fence', north='false', south='false', east='false', west='false', waterlogged='false'), 'table-base')
            p.block((w // 2, 1, 1), state_of('birch_pressure_plate', powered='false'), 'tabletop')
        elif self.purpose == 'study':
            for x in range(w):
                p.block((x, 0, 0), state_of('bookshelf'), 'bookcase')
                if x in (0, w - 1):
                    p.block((x, 1, 0), state_of('bookshelf'), 'bookcase')
                p.block((x, 2, 0), slab('dark_oak'), 'bookcase-cornice')
            p.block((0, 0, 1), state_of('lectern', facing='south', has_book='false', powered='false'), 'reading-desk')
            p.block((w - 1, 0, 1), stairs('dark_oak', 'north'), 'reading-seat')
        elif self.purpose == 'cooking':
            for x in range(w):
                material = state_of('smoker', facing='south', lit='false') if x == 0 else state_of('water_cauldron', level='3') if x == w - 1 else barrel
                p.block((x, 0, 0), material, 'cooking-counter', nbt=supplies() if x not in (0, w - 1) else None)
                p.block((x, 2, 0), slab('dark_oak', 'top'), 'pot-shelf')
            p.block((0, 1, 0), state_of('iron_trapdoor', facing='north', half='top', open='false', powered='false', waterlogged='false'), 'stove-hood')
            p.block((0, 0, 1), state_of('crafting_table'), 'preparation')
            p.block((w - 1, 0, 1), state_of('brown_carpet'), 'work-mat')
        elif self.purpose == 'craft':
            for x in range(w):
                p.block((x, 0, 0), state_of('crafting_table' if x == 0 else 'smithing_table'), 'workbench')
                p.block((x, 2, 0), slab('dark_oak', 'top'), 'tool-shelf')
            p.block((0, 0, 1), state_of('anvil', facing='north'), 'anvil')
            p.block((w - 1, 0, 1), barrel, 'supplies', nbt=supplies())
        else:
            for x in range(w):
                for y in range(2):
                    p.block((x, y, 0), barrel, 'cabinet', nbt=supplies())
                p.block((x, 2, 0), slab('dark_oak'), 'cabinet-cornice')
                p.block((x, 0, 1), state_of('brown_carpet'), 'storage-runner')
        return p
