name: invoice_explanation
version: 2
start: preparar

nodes:
  - id: preparar
    action: preparar_invoice_explanation
    input:
      msisdn: $.input.msisdn
      customer_id: $.input.customer_id
      current_invoice_number: $.input.current_invoice_number
      past_invoice_number: $.input.past_invoice_number
      current_invoice_due_date: $.input.current_invoice_due_date
      past_invoice_due_date: $.input.past_invoice_due_date
      channel: $.input.channel
      tentativa_anterior: $.vars.preparar.tentativa
      invoice_explanation_base: $.input.invoice_explanation_base

  - id: formatar
    action: formatar_invoice_explanation
    input:
      explicacao_base: $.vars.preparar.explicacao_base
      invoice_detail: $.input.invoice_detail
    # A pausa faz parte do contrato do workflow, não da action de formatação.
    # Depois de apresentar a explicação, sempre aguardamos SIM/NAO antes de
    # entrar em `decisao`. A action `formatar_invoice_explanation` permanece
    # responsável apenas por montar a mensagem.
    pause:
      enabled: true
      return_from: $.output.mensagem
      expected_input:
        key: resposta_usuario
        allowed_values: ["SIM", "NAO", "CONTINUAR"]
        normalize: upper_strip
        reprompt: "Não entendi. Essa explicação resolveu sua dúvida? Responda sim ou não."
        semantic_classifier:
          enabled: true
          include_relevant_context: true
          # Saída sentinela fora de allowed_values. Quando usada, o framework
          # não retoma o workflow e devolve o reprompt declarado acima.
          unmatched_value: OUTRO
          option_actions:
            CONTINUAR:
              action: contextual_reentry
          prompt: |
            Classifique a fala do cliente em uma das opções de {{ allowed_values }}.
            Se a fala não tiver significado suficiente no contexto para escolher com segurança
            SIM, NAO ou CONTINUAR, retorne OUTRO.

            A pergunta pendente é:
            {{ pending_prompt }}

            Contexto conversacional relevante imediatamente anterior a esta decisão:
            {{ relevant_conversation_context }}

            A fala atual do cliente é:
            {{ user_input }}

            Para este workflow:
            - SIM: use somente quando o cliente indicar entendimento, aceitação ou encerramento da dúvida,
              sem introduzir nova pergunta, hipótese, valor, referência ou fato a validar.
            - NAO: use quando o cliente responder negativamente à pergunta pendente ou disser de forma
              explícita que a explicação não resolveu sua dúvida. Exemplos: "não", "de jeito nenhum",
              "não resolveu", "ainda não entendi".
            - CONTINUAR: use quando a fala for compreensível, mas não responder diretamente SIM ou NAO e,
              considerando o contexto imediatamente anterior, complementar, especificar ou continuar a
              solicitação que originou a pergunta pendente. Inclua novas perguntas, hipóteses, valores,
              referências e fatos propostos pelo cliente que ainda precisem ser validados.
            - OUTRO: use somente quando a fala for incompreensível, desconexa, fragmentária ou não tiver
              significado suficiente para responder à pergunta pendente nem continuar a solicitação.

            Exemplos:
            - "sim", "legal", "ok", "beleza", "entendi", "obrigado" => SIM
            - "não", "de jeito nenhum", "não resolveu", "ainda não entendi" => NAO
            - contexto: "tem uma cobrança aqui que eu não reconheço"; fala: "é a de quatorze e noventa e nove" => CONTINUAR
            - "então minha fatura ficaria R$ 275,00, certo?" => CONTINUAR
            - "quer dizer que no próximo mês vou pagar menos?" => CONTINUAR
            - palavra isolada ou fragmento sem relação semântica suficiente com a pergunta => OUTRO

            Regras de segurança:
            - Nunca trate pergunta, hipótese, valor, referência ou fato proposto pelo cliente como concordância.
            - CONTINUAR não confirma nem ratifica nenhum dado dito pelo cliente; apenas solicita reentrada
              contextual para nova validação pelas fontes de negócio.
            - Para fala compreensível, retorne somente uma das opções oferecidas em {{ allowed_values }}.
            - Para fala incompreensível ou sem significado contextual suficiente, retorne somente OUTRO.
      resume_from: decisao

  - id: checar_tentativa
    action: checar_tentativa_cvn
    input:
      tentativa: $.vars.preparar.tentativa

  - id: texto_intencao_invalida
    action: montar_resposta_texto
    input:
      dados:
        texto_usuario: "Não consegui validar sua solicitação. Pode informar novamente sobre a sua fatura?"

  - id: fim_intencao_invalida
    action: montar_resposta_texto
    input:
      dados:
        texto_usuario: "Não foi possível validar sua solicitação neste momento."

  - id: resposta_falha_servico
    action: montar_resposta_texto
    input:
      dados:
        texto_usuario: "Para continuar com a sua solicitação, aguarde um instante."

  - id: decisao
    action: no_op
    input: {}

  - id: registrar_sim
    action: registrar_atendimento_invoice_explanation
    input:
      resposta_usuario: SIM

  - id: registrar_protocolo_aceite
    action: registrar_protocolo_inicio
    input:
      msisdn: $.input.msisdn
      scenario: invoice_explanation_aceite_fechado
      request_status: Fechado
      status: CLOSED
      workflow_response_final: true
      mensagem_final: "Seu número de protocolo é {protocol}."

  - id: registrar_nao
    action: registrar_atendimento_invoice_explanation
    input:
      resposta_usuario: NAO

  # Política de jornada do agente Contas: uma negativa à pergunta de confirmação da
  # explicação transfere o atendimento para continuidade humana. A primitive de
  # HUMAN_HANDOFF é do framework; a decisão e a fraseologia ficam declaradas aqui.
  - id: handoff_pos_explicacao_nao
    action: preparar_handoff_invoice_explanation
    input:
      mensagem: "Para continuar com a sua solicitação, aguarde um instante."
      reason: invoice_explanation_not_resolved

  # A variação foi causada por VAS avulso ou estratégico? Sem VAS variado não há nada que
  # o bot resolva, e insistir com o orquestrador só gasta turno (SPEC §9 "Explicação da variação recusada").
  - id: checar_vas_variacao
    action: checar_vas_variado
    input:
      invoice_variation: $.input.invoice_variation
      invoice_detail: $.input.invoice_detail

  # Nó só para nomear o last_node: o backend o mapeia para nao_resolvido em
  # auto_finalize_status_map, e a fala vem do NAO_RESOLVIDO_CLOSING.
  - id: finalizar_nao_resolvido
    action: no_op
    input: {}

edges:
  - from: preparar
    to: formatar
    priority: 10
    when:
      eq: [$.vars.preparar.success, true]

  - from: preparar
    to: resposta_falha_servico
    priority: 20
    when:
      eq: [$.vars.preparar.service_failed, true]

  - from: preparar
    to: checar_tentativa
    priority: 30
    when:
      eq: [$.vars.preparar.success, false]

  - from: checar_tentativa
    to: fim_intencao_invalida
    priority: 10
    when:
      eq: [$.vars.checar_tentativa.limite_excedido, true]

  - from: checar_tentativa
    to: texto_intencao_invalida
    priority: 20

  - from: formatar
    to: decisao

  - from: decisao
    to: registrar_sim
    priority: 10
    when:
      eq: [$.input.resposta_usuario, SIM]

  - from: decisao
    to: registrar_nao
    priority: 20
    when:
      eq: [$.input.resposta_usuario, NAO]

  - from: registrar_sim
    to: registrar_protocolo_aceite

  - from: registrar_protocolo_aceite
    to: END

  - from: registrar_nao
    to: handoff_pos_explicacao_nao

  - from: handoff_pos_explicacao_nao
    to: END

  - from: checar_vas_variacao
    to: finalizar_nao_resolvido
    priority: 10
    when:
      eq: [$.vars.checar_vas_variacao.tem_vas_variado, false]

  # Tem VAS variado (ou não deu para saber): devolve ao orquestrador, como sempre.
  - from: checar_vas_variacao
    to: END
    priority: 20

  - from: finalizar_nao_resolvido
    to: END

  - from: texto_intencao_invalida
    to: END

  - from: fim_intencao_invalida
    to: END

  - from: resposta_falha_servico
    to: END
