"""Keep task goal units: CLI gained is an item count, never ten gather actions."""
from ..catalog import normalized
from ..game_connector import successful, paid_actions_enabled
from .contracts import require, integer
from .readiness import suggested_output
from .trigger_engine import TriggerEngine


def gather_route(task,catalog):
    if task.module!='gather' or 'file_route' in task.options:return ''
    if normalized(task.skill)=='낚시':return ''  # Named fish ≠ the selected fishing spot.
    if task.goal.kind not in ('quantity','minutes','until_stopped'):return ''
    if task.goal.kind=='quantity' and task.goal.amount<100:return ''
    known=suggested_output(task,catalog)
    selected=task.options.get('output_item') or known
    return selected if known and selected==known else ''


def plan_text(tasks,catalog,config):
    from ..game_connector import inventory_enabled
    inventory='재고 판단: '+('공식 CLI 전체 목록 (채집·가공은 양쪽 모드 공통, 가방/창고·잠금 구분, 사용 직전 다시 조회)' if inventory_enabled(config,life=any(t.module in ('gather','processing') for t in tasks)) else '기존 화면 판독')
    movement='이동용 날개·T 이동: 두 모드 모두 기존 경로 유지. CLI 실행 날개 한도와 별도.'
    tools='생활 도구: ToolOk=false → 수리 허용 시 NPC 수리·도구만 재장착 1회 → CLI 재확인. 계속 false이면 중단. 내구도 수치 추정 없음.'
    fishing=f"낚시 예외: 지정 낚시터까지 클릭/T 이동 → 현장에서 항상 CLI 시작(5개). 상단 OFF와 무관, CLI 실행 날개 한도 {config['wing_limit']}개는 적용. 수량 목표 도달 시 무료 CLI 중지."
    if not paid_actions_enabled(config):return 'CLI 실행용 날개: 사용 안 함 · 낚시 외 해당 행동은 좌표 클릭\n'+movement+'\n'+fishing+'\n'+inventory+'\n'+tools+'\n기존 완료품 전체 수령: 지원되는 경우 무료 CLI 공통 사용.'
    lines=[f"CLI 실행용 날개: 사용 · 미지원 조건 클릭 보완\nCLI 실행 날개 한도: 이번 실행 총 {config['wing_limit']}개 (채집·제작·가공 호출당 현재 5개).",movement,fishing,tools,
        '재시도: '+('자연 중단은 날개 한도 내 재시도' if config['retry_stopped'] else '중단 후 확인')+' · 사용자 중단/불확실 응답은 재호출하지 않음.',
        '채집 단위: 클릭은 기본100회이며 패킷의 행동 횟수로 중지. CLI는 기본100개이며 수량·무한 채집만 지원. 획득량을 행동 횟수로 환산하지 않음. 낚시는 현장 CLI 연속 실행.',
        '수동 중단 시 추가 명령은 보내지 않으며 이미 시작한 게임 행동은 계속될 수 있습니다. CLI의 최종 응답을 기다린 뒤 종료합니다.']
    for i,t in enumerate(tasks,1):
        route=('낚시: 지정 낚시터 클릭/T 이동 + 현장 CLI 자동 낚시') if t.module=='gather' and normalized(t.skill)=='낚시' else ('채집: 정확한 품목 CLI · 단일 명령 지정 불가 품목은 등록 좌표 클릭 보완' if t.module=='gather' else ('가공: 정확한 CLI 이름 또는 재료 변형별 등록 좌표 · 재료/완료 목록 CLI · 개별 신규 슬롯 수령' if t.module=='processing' else '기존 실행 경로 유지'))
        lines.append(f'{i}. {route}')
    return '\n'.join(lines+[inventory])


class ConnectorEngine(TriggerEngine):
    def __init__(self,*args,connector,**kwargs):
        super().__init__(*args,**kwargs)
        self.connector=connector

    def restart_task(self,task,state):
        if state.get('connector_gather'):
            require(not self.journal.restart_blockers(task.id),'커넥터 소비 결과가 불확실합니다. 재호출하지 않습니다.')
            # Replay completed CLI receipt using the SAME key, then checkpoint
            # its gain exactly once. Do not discard the pending receipt cursor.
            return
        return super().restart_task(task,state)

    def support(self,task,root,*,combat=False,reserves=None,reported=None,tool_item=None):
        if not combat and task.module=='gather' and reported=='tools_broken' and self.connector.supports('get_gatherable_items'):
            from .policy import common
            result=self.op(root,'repair_unavailable_tool',skill=task.skill,tool_item=tool_item,
                           repair_policy=common(task))
            require(result.get('tool_ready') is True,'공식 도구 사용 가능 상태 미확인')
            return
        original=self.sale_allowlist
        if not combat and task.module=='gather':
            from .sale_service import verified_sale_materials
            self.sale_allowlist=verified_sale_materials(self.connector)
        try:return super().support(task,root,combat=combat,reserves=reserves,reported=reported)
        finally:self.sale_allowlist=original

    def processing(self,task,state,progress):
        return super().processing(task,state,progress)

    def gather(self,task,state,progress):
        if getattr(self,'direct_life',False):
            # Backend choice belongs inside the common admitted operation,
            # not separate controllers with different goal/partial semantics.
            if state.get('connector_gather') and progress.in_flight:
                prefix=task.id+('/restart/'+str(state['restart_generation']) if state.get('restart_generation') else '')
                key=prefix+'/connector_gather/'+str(state.get('unit',0))+'/connector_gather'
                result=self.journal.completed_result(key)
                require(isinstance(result,dict),'이전 CLI 채집 결과 미정산 · 새로운 시작을 보내지 않습니다')
                self.record_gather_result(task,state,progress,result)
                if progress.reached(task,self.now()):return
            state.pop('connector_gather',None)
            return TriggerEngine.gather(self,task,state,progress)
        if not paid_actions_enabled(self.connector.config):
            if state.get('connector_gather') and progress.in_flight:
                # Switching OFF must neither discard an already returned gain
                # nor start a second action while its receipt is unresolved.
                prefix=task.id+('/restart/'+str(state['restart_generation']) if state.get('restart_generation') else '')
                key=prefix+'/connector_gather/'+str(state.get('unit',0))+'/connector_gather'
                result=self.journal.completed_result(key)
                require(isinstance(result,dict),'이전 CLI 채집 응답이 미정산 상태입니다. 새 클릭/CLI 입력 없이 결과 확인이 필요합니다.')
                self.record_gather_result(task,state,progress,result)
                if progress.reached(task,self.now()):return
            return super().gather(task,state,progress)
        name=gather_route(task,self.catalog)
        if not name or not self.connector.supports('execute_gathering','get_gatherable_items','get_activity'):
            return super().gather(task,state,progress)
        state['connector_gather']=True
        while self.admission(task,state,progress):
            # The API has no quantity argument. Preserve the user's goal instead
            # of pretending it accepted a smaller cap or wasting another wing call.
            if task.goal.kind=='quantity' and task.goal.amount-progress.acquired<100:
                self.event('control_backend',dict(backend='click',operation='native_gather',message='클릭 보완 · 100개 미만 잔여 수량'))
                return super().gather(task,state,progress)
            root=task.id+'/connector_gather/'+str(state.get('unit',0))
            result=self.op(root,'connector_gather',consuming=True,name=name)
            self.record_gather_result(task,state,progress,result)
            if result.get('error') in ('tool_broken','tool_missing'):
                self.support(task,root+'/support',reported='tools_broken',tool_item=name)
            self.check()

    def record_gather_result(self,task,state,progress,result):
        gained=integer(result.get('gained',0),'커넥터 획득 수량')
        if 'gained' in result or result.get('result') in ('completed','stopped'):
            target=integer(result.get('target'),'커넥터 목표 수량',1)
            integer(result.get('gained'),'커넥터 획득 수량')
            require(gained<=target<=100,'커넥터 획득/목표 수량 범위 변경')
            if result.get('result')=='completed':require(gained==target,'커넥터 완료 수량 미확인')
        progress.acquired+=gained
        state['connector_no_progress']=state.get('connector_no_progress',0)+1 if gained==0 else 0
        self.finish_unit(task,state,progress,actions=0)
        if result.get('error') in ('tool_broken','tool_missing') and not result.get('_interrupted'):
            require(state['connector_no_progress']<2,'도구 오류/획득0이 2회 연속 발생 · 추가 CLI 소모 중단')
            return  # Confirmed partial gains persist before the repair branch.
        successful(result)  # Persist confirmed partial gain before stopping.
        require(result.get('result') in ('completed','stopped'),'커넥터 채집 종료 미확인: '+str(result))
        if result['result']=='stopped':
            require(self.connector.config['retry_stopped'],'커넥터 채집 중단 · 자동 재시도 설정 꺼짐')
            require(state['connector_no_progress']<2,'획득 없이 2회 연속 중단 · 날개 추가 소모 방지')
