class Contabilidade::GrupoDeRetencaoDoControleDePagamento < ApplicationRecord
  has_paper_trail

  attr_default :por_unidade_gestora, true

  belongs_to :controle_de_pagamento, required: true
  belongs_to :conta_extra_orcamentaria, required: true

  has_many :conjuntos_de_contas_do_grupo_de_retencao, dependent: :destroy
  has_many :liquidacoes_do_grupo_de_retencao, dependent: :destroy
  has_many :liquidacoes, through: :liquidacoes_do_grupo_de_retencao

  validates :por_unidade_gestora, presence: true, if: proc { por_fonte.nil? && persisted? }
  validates :por_fonte, presence: true, if: proc { por_unidade_gestora.nil? && persisted? }

  validate :valor_dos_conjuntos_nao_pode_ultrapassar_o_valor_retido, if: proc { liquidacoes_cadastradas_no_form.any? }

  before_update :cria_conjuntos_de_contas, if: proc { por_fonte_changed? || conjuntos_de_contas_do_grupo_de_retencao.empty? }

  accepts_nested_attributes_for :conjuntos_de_contas_do_grupo_de_retencao, reject_if: :all_blank, allow_destroy: true

  enum acao: {
    pagar: 1,
		pagar_recolher: 2,
		transferir: 3,
  }

  def descricao_da_acao
    case acao
    when "pagar"
      "Ação PAGAR: Lançamento da despesa extra orçamentária na Unidade Gestora do Empenho para o credor associado a conta extra. Conta Origem Obrigatória"
    when "pagar_recolher"
      "Ação Pagar/Recolher: Lançamento da despesa extra orçamentária na Unidade Gestora do Empenho para o credor associado a Unidade Gestora da conta destino. Lançamento de Receita Extra Orçamentária ou Receita Orçamentária para a Unidade Gestora da conta destino tendo como contribuinte a pessoa associada a unidade gestora do empenho.Contas Origem e Destino obrigatórias."
    when "transferir"
      "Ação Transferir: Opção de transferir o valor da retenção para outra conta corrente da unidade gestora do empenho. Ação opcional do usuário."
    end
  end

  def conjuntos_de_contas_para_o_form(unidade_orcamentaria_id, fonte_de_recursos_id)
    conjuntos_de_contas_do_grupo_de_retencao.select{ |conjunto_de_conta| 
      conjunto_de_conta.unidade_orcamentaria_id == unidade_orcamentaria_id && conjunto_de_conta.fonte_de_recursos_id == fonte_de_recursos_id &&
      (conjunto_de_conta.conjunto_padrao? || conjunto_de_conta.cadastrado_no_form?)
    }.sort_by { |conjunto_de_conta| conjunto_de_conta.conjunto_padrao? ? 0 : 1}
  end

  def conjunto_totalmente_preenchido?
    liquidacoes.sum(&:valor_das_retencoes) == conjuntos_de_contas_do_grupo_de_retencao.where(conjunto_padrao: [false,nil]).sum(:valor)
  end

  private
  def liquidacoes_cadastradas_no_form
    conjuntos_de_contas_do_grupo_de_retencao.reject(&:marked_for_destruction?).select(&:cadastrado_no_form)
  end

  def valor_dos_conjuntos_nao_pode_ultrapassar_o_valor_retido
    liquidacoes.each do |liquidacao|
      conjuntos_de_conta = liquidacoes_cadastradas_no_form.select{ |conjunto| conjunto.liquidacao_id == liquidacao.id }

      if conjuntos_de_conta.sum(&:valor).to_d > liquidacao.valor_das_retencoes.to_d
        errors.add(:valor_total_retido, "Soma dos valores retidos na liquidacao #{liquidacao.empenho_e_numero} não pode ultrapassar #{liquidacao.valor_das_retencoes.real_contabil}")
      end
    end
  end

  def cria_conjuntos_de_contas
    conjuntos_de_contas_do_grupo_de_retencao.delete_all
    liquidacoes = Contabilidade::Liquidacao.where(id: liquidacoes_do_grupo_de_retencao.pluck(:liquidacao_id))

    if por_fonte? == false
      liquidacoes.group_by(&:unidade_orcamentaria).each do |unidade_orcamentaria, liquidacoes|
        Contabilidade::ConjuntoDeContasDoGrupoDeRetencao.create!({
          unidade_orcamentaria_id: unidade_orcamentaria.id,
          grupo_de_retencao_do_controle_de_pagamento_id: id,
          conjunto_padrao: true,
          valor: liquidacoes.sum(&:valor_das_retencoes)
        })
      end
    else
      liquidacoes.group_by{ |liquidacao| [liquidacao.unidade_orcamentaria, liquidacao.fonte_de_recursos] }.each do |criterios, liquidacoes|
        unidade_orcamentaria = criterios[0]
        fonte_de_recursos = criterios[1]
        Contabilidade::ConjuntoDeContasDoGrupoDeRetencao.create!({
          unidade_orcamentaria_id: unidade_orcamentaria.id,
          fonte_de_recursos: fonte_de_recursos.id,
          grupo_de_retencao_do_controle_de_pagamento: id,
          conjunto_padrao: true,
          valor: liquidacoes.sum(&:valor_das_retencoes)
        })
      end
    end
  end
end
