"""Merge adapter; uses the existing worker, reader and protected map engine.

No controller monkey patch, new worker, UAC, input transport or live I/O on import.
"""
from copy import deepcopy
from .contracts import Atlas, fresh, require

class MapModule:
    def __init__(self, controller, root=None):
        self.controller=controller
        self.atlas=Atlas(root)
        self.bundles={self.atlas.bundle['bundle_id']:self.atlas}
        from .reader import advisory_factory
        self.read_session=advisory_factory(controller._map_session_factory)

    def reload_bundle(self, root):
        """Host calls after explicit local folder selection. Old bundle objects/files stay intact."""
        candidate=Atlas(root)
        with self.controller.lock:
            self.controller._idle()
            self.bundles[candidate.bundle['bundle_id']]=candidate
            self.atlas=candidate
        return candidate.version_status()

    def atlas_for(self, payload):
        require(payload.get('bundle_id') in self.bundles,'목적지가 사용한 이전 지도 묶음을 다시 불러와 주세요.')
        return self.bundles[payload['bundle_id']]

    def state(self):
        workspace=self.controller.map_workspace
        with workspace.lock:
            snapshot=deepcopy(workspace.current)
        return dict(snapshot=snapshot,live=bool(snapshot and fresh(snapshot)),game_inputs=0,
                    bundle=self.atlas.version_status((snapshot or {}).get('source_version')))

    def enqueue(self, payload):
        """Call only from the explicit 이동 button; queue registration sends no input."""
        p,title=self.prepare(payload)
        c=self.controller
        with c.lock:
            c._idle()
            return dict(id=c.operation_queue.add(p,title),queued=True,game_inputs=0)

    def prepare(self, payload, *, waiting_allowed=False):
        """Shared no-input validation for the old queue and a reviewed Sukja draft."""
        atlas=self.atlas_for(payload);p=atlas.validate(payload)
        c=self.controller
        with c.lock:
            if not waiting_allowed:c._idle()
            # Bind server-side observed owner; ignore client claims about current state.
            state=self.state()
            from .contracts import current_owner
            owner=current_owner(state['snapshot']) if state['live'] else None
            claimed=p['destination']['expected_owner']
            require(claimed is None or owner==claimed,'선택 이후 현재 연결이 바뀌었습니다. 다시 선택해 주세요.')
            p['destination']['expected_owner']=owner
            target=atlas.marker(p['destination']['marker_key'])['name'] if p['method']=='spot' else '선택 위치'
            title=atlas.resource(p['destination']['resource'])['title']+' · '+target+'로 이동'
            return p,title

    def launch(self, payload):
        """Only existing OperationQueue dispatcher may call this entry point."""
        c=self.controller
        import threading
        require(c.execution_queue.active and c.execution_queue.dispatch_thread==threading.get_ident(),
                '기존 운용 큐 실행 경로에서만 이동을 실행합니다.')
        atlas=self.atlas_for(payload);p=atlas.validate(payload)
        with c.lock:
            c._idle()
            require(not(c._map_read_worker and c._map_read_worker.is_alive()),'지도 읽기 완료 후 실행해 주세요.')
        return c._launch('map_move',p,c._automation,lambda service:execute(service,p,atlas,
            observer_factory=self.read_session,publish=c.map_workspace.observe))

def execute(service, payload, atlas, *, observer_factory, publish=lambda _:None):
    """Actual future runtime call; never invoked by preview or the offline check."""
    from mini_masukja.map_movement import MapMovementEngine
    p=atlas.validate(payload)
    request=atlas.request(p)
    class ResourceBoundEngine(MapMovementEngine):
        _bound=False
        def _select_region(self, session, world):
            super()._select_region(session,world)
            atlas.verify_current(p,self.current)
            self._bound=True
        def _pose(self, snapshot):
            # Every destination/pan/long-press coordinate uses the freshly read pose.
            if self._bound: atlas.verify_current(p,snapshot)
            return super()._pose(snapshot)
        def _wait_selected(self, session, request):
            snapshot,selected=super()._wait_selected(session,request)
            atlas.verify_current(p,snapshot)
            return snapshot,selected
    engine=ResourceBoundEngine(service,observer_factory=observer_factory,publish=publish,
        expected_owner=p['destination']['expected_owner'])
    return engine.run(request)
