"""Join an explicit current DeliverUI NPC ID to its current source group.

The UI retains a definition ID and group identifier, not an EntityKey. A zero
UI NPC ID uses only the separately pinned logical group request route; it is
never replaced with a nearby/generated group candidate.
"""
from copy import deepcopy
import struct


def read_delivery_group(session, component):
    from .group_npc_observer import GroupNPCSession, source_pins
    pins = source_pins()
    shape = session.source_shape('DeliverUIViewModelComponent')
    row = next(f for f in shape['fields'] if f['name'] == 'targetNPCGroupTagName')
    unique = next(s for s in pins['classes'] if s['name'] == 'UniqueString')
    if (row['type'].get('definition_index') != unique['type_index']
            or row['type'].get('type_code') != 17 or unique['type_definition_size_raw'][1] != 16):
        raise ValueError('Current delivery group identifier source type changed')
    offset = next(f['offset']-16 for f in unique['fields'] if f['name']=='actualString')
    fields = session.typed_fields(component, 'DeliverUIViewModelComponent')
    raw = session.watch(component+fields['targetNPCGroupTagName'],16)
    pointer = struct.unpack_from('<Q',raw,offset)[0]
    if not pointer:
        return None
    view = GroupNPCSession.__new__(GroupNPCSession)
    for key in ('reader','base','plan','character_plan','_guards'):
        setattr(view,key,getattr(session,key))
    group = view.string(pointer)
    if not group:
        return None
    npc = session.inline_value(component,'DeliverUIViewModelComponent','targetNPCSheetId','NPCSheetId','Id')
    result = dict(group_name=group,npc_id=npc,confirmed=False,
                  basis='current DeliverUIViewModelComponent target NPC definition and group identifier',
                  source='current delivery UI NPC ID joined to current NPCSheetData.NPCGroupId',
                  source_hash=pins['source_hash'],source_version={k:pins[k] for k in ('metadata_sha256','game_assembly_sha256')},
                  entity_key_available=False)
    if type(npc) is not int or not (npc & 0xffffffff):
        try:
            from .quest_item_delivery_request import read_group_request
            return read_group_request(session,component,group)
        except (ValueError,RuntimeError,OSError,KeyError,TypeError,AttributeError) as exc:
            return dict(result,reason='current group request route unavailable: '+str(exc))
    view.verify_native()
    members = [m for m in view.members(group) if (m['npc_id'] & 0xffffffff) == (npc & 0xffffffff)]
    if len(members) != 1:
        return dict(result,reason='current explicit delivery NPC is not a unique member of the exact group')
    session.assert_stable()
    return dict(result,confirmed=True,membership=deepcopy(members[0]))


def delivery_group_npc(snapshot, node):
    """Only the UI's own nonzero NPC ID resolves a typed group NPC operand."""
    from .group_npc_observer import source_pins
    typed = (node.get('params') or {}).get('typed_operands') or {}
    group = (typed.get('operands') or {}).get('npc_group_tag') or {}
    if not group:
        return None
    details = snapshot.get('details') or {};proof = details.get('delivery_group') or {}
    pins = source_pins();npc = details.get('target_npc_id')
    membership = proof.get('membership') or {}
    if (proof.get('confirmed') is not True or not group.get('value')
            or proof.get('group_name') != group['value'] or type(npc) is not int or not (npc & 0xffffffff)
            or proof.get('npc_id') != npc or proof.get('source_hash') != pins['source_hash']
            or any((proof.get('source_version') or {}).get(k) != pins[k] for k in ('metadata_sha256','game_assembly_sha256'))
            or membership.get('verified') is not True or membership.get('group_name') != group['value']
            or membership.get('npc_id') != npc):
        raise ValueError('current delivery UI lacks an explicit exact NPC/group membership owner')
    return dict(table_domain='NPCSheet',id=npc,raw_id=npc,
                source='current DeliverUI targetNPCSheetId + exact current group membership',group_proof=deepcopy(proof))
