class Loa::FonteDaCotaOrcamentaria < ApplicationRecord
  has_paper_trail

  attr_default :valor, 0
  attr_default :percentual, 0
  attr_default :empenhado_ano_anterior, 0
  attr_default :percentual_empenho_ano_anterior, 0
  attr_default :liquidado_ate_o_mes, 0
  attr_default :valor_proposto, 0
  attr_default :percentual_proposto, 0

  belongs_to :cota_orcamentaria, class_name: "Loa::CotaOrcamentaria"
  belongs_to :fonte_de_recursos, class_name: "Base::FonteDeRecursos"
  belongs_to :fonte_de_recursos_do_ano_anterior, class_name: "Base::FonteDeRecursos", foreign_key: :fonte_de_recursos_do_ano_anterior_id
  has_many :doccs, class_name: "Loa::Docc", dependent: :destroy
  has_many :propostas_orcamentarias_setoriais, class_name: "Loa::PropostaOrcamentariaSetorial", dependent: :destroy

  validates :doccs, uniq_nested_attributes: { atributo: :orcamento_da_despesa_id, mensagem: "Orçamento da despesa deve ser único por fonte de recurso e unidade orçamentária." }
  accepts_nested_attributes_for :doccs, reject_if: :all_blank, allow_destroy: true
  validates_associated :doccs

  validates :propostas_orcamentarias_setoriais, uniq_nested_attributes: { atributo: :orcamento_da_despesa_id, mensagem: "Orçamento da despesa deve ser único por fonte de recurso e unidade orçamentária." }
  accepts_nested_attributes_for :propostas_orcamentarias_setoriais, reject_if: :all_blank, allow_destroy: true
  validates_associated :propostas_orcamentarias_setoriais


  validates_presence_of :cota_orcamentaria_id, :fonte_de_recursos_id, :valor, :percentual, :empenhado_ano_anterior, :percentual_empenho_ano_anterior, :liquidado_ate_o_mes, :valor_proposto, :percentual_proposto

  #validate :valida_saldo_da_fonte, :valida_valor_distribuido

  before_save :calcular_valor_empenhado_no_ano_anterior, :calcular_valor_liquidado_ate_o_mes

  def valida_saldo_da_fonte
    if (self.valor_distribuido_por_fonte + self.valor - self.valor_was).to_d > self.valor_total_por_fonte.to_d
      errors.add(:valor, "O valor informado ultrapassa o valor total da fonte.")
    end
  end

  # def valida_valor_distribuido
  #   if ((self.doccs.map { |d| d.attributes["valor"].to_d }.sum + self.propostas_orcamentarias_setoriais.map { |d| d.attributes["valor"].to_d }.sum) > self.valor.to_d)
  #     errors.add(:base, "O valor distribuido ultrapassa o valor total da fonte.")
  #   end
  # end

  def calcular_valor_empenhado_no_ano_anterior
    valor_empenhado = Contabilidade::Empenho
      .joins(:orcamento_da_despesa).includes(:orcamento_da_despesa)
      .where("data_do_empenho between ? and ?", Date.new(contexto_atual.orcamento_anterior.orcamento_anterior.exercicio, 1, 1), Date.new(contexto_atual.orcamento_anterior.orcamento_anterior.exercicio, 12, 31))
      .where(unidade_orcamentaria_id: cota_orcamentaria.unidade_orcamentaria_exercicio_anterior.id, orcamento_id: contexto_atual.orcamento_anterior.orcamento_anterior.id)
      .where(loa_orcamentos_da_despesa: {fonte_de_recursos_id: fonte_de_recursos_do_ano_anterior.id})
      .confirmados_ou_anulados_e_superiores.do_orcamento.sum(&:saldo_total)

    valor_anulado = Contabilidade::AnulacaoDoEmpenho
      .joins(empenho: :orcamento_da_despesa).includes(empenho: :orcamento_da_despesa)
      .where("data_da_anulacao between ? and ?", Date.new(contexto_atual.orcamento_anterior.orcamento_anterior.exercicio, 1, 1), Date.new(contexto_atual.orcamento_anterior.orcamento_anterior.exercicio, 12, 31))
      .where(contabilidade_empenhos: { unidade_orcamentaria_id: cota_orcamentaria.unidade_orcamentaria_exercicio_anterior.id, orcamento_id: contexto_atual.orcamento_anterior.orcamento_anterior.id})
      .where(loa_orcamentos_da_despesa: {fonte_de_recursos_id: fonte_de_recursos_do_ano_anterior.id})
      .confirmadas.do_orcamento.sum(&:valor)

    self.empenhado_ano_anterior = valor_empenhado - valor_anulado
  end

  def calcular_valor_liquidado_ate_o_mes
    ultimo_lote_do_sim_enviado = Tcm::Lote.where(tipo: :contabilidade, orcamento: contexto_atual.orcamento_anterior, situacao: :finalizado).order(:mes_de_referencia).last
    data_final = Date.new(contexto_atual.orcamento_anterior.exercicio, ultimo_lote_do_sim_enviado.read_attribute_before_type_cast(:mes_de_referencia).to_i, 1).end_of_month

    unidade = contexto_atual.orcamento_anterior.unidades_orcamentarias.select { |i| i.codigo_completo == cota_orcamentaria.unidade_orcamentaria_exercicio_anterior.codigo_completo }.first
    fonte = contexto_atual.orcamento_anterior.fontes_de_recursos.select { |i| i.codigo_completo == fonte_de_recursos_do_ano_anterior.codigo_completo }.first
    
    self.liquidado_ate_o_mes = Contabilidade::Liquidacao.joins(empenho: :orcamento_da_despesa).includes(empenho: :orcamento_da_despesa)
      .where("data_da_liquidacao between ? and ?", Date.new(contexto_atual.orcamento_anterior.exercicio, 1, 1), data_final)
      .where(contabilidade_empenhos: {unidade_orcamentaria_id: unidade.id})
      .where(loa_orcamentos_da_despesa: {fonte_de_recursos_id: fonte.id})
      .confirmadas_ate_autorizadas.nao_estornada.do_orcamento.sum(&:valor)
    
    return self.liquidado_ate_o_mes
  end

  def calcular_valor_proposto
    self.valor_proposto = (self.percentual_empenho_ano_anterior / 100) * self.valor_total_por_fonte
  end
  
  def valor_total_por_fonte
    # # retirar orcamento anterior, temporário enquando faço a rotina pois não tenho dados em 2025
    # # trocar por unidade e fonte do exercicio atual
    # fonte = contexto_atual.orcamento_anterior.fontes_de_recursos.select { |i| i.codigo_completo == fonte_de_recursos_do_ano_anterior.codigo_completo }.first
    # self.cota_orcamentaria.orcamento.orcamento_anterior.orcamentos_da_receita
    #   .joins(:fonte_de_recursos).includes(:fonte_de_recursos)
    #   .where(loa_orcamentos_da_receita: {fonte_de_recursos_id: fonte.id})
    #   .sum(&:valor)

    self.cota_orcamentaria.orcamento.orcamentos_da_receita
      .joins(:fonte_de_recursos).includes(:fonte_de_recursos)
      .where(loa_orcamentos_da_receita: {fonte_de_recursos_id: fonte_de_recursos_id})
      .sum(&:valor)
  end

  def valor_distribuido_por_fonte
    Loa::FonteDaCotaOrcamentaria
      .joins(:cota_orcamentaria).includes(:cota_orcamentaria)
      .where(loa_cotas_orcamentarias: {orcamento_id: contexto_atual.id})
      .where(fonte_de_recursos_id: self.fonte_de_recursos_id)
      .sum(:valor)
  end

  def saldo_da_fonte
    self.valor_total_por_fonte - self.valor_distribuido_por_fonte - self.valor + self.valor_was
  end

  def valor_utilizado
    Loa::OrcamentoDaDespesa
      .joins(elemento_de_despesa_por_subacao: :subacao)
      .where(loa_subacoes: {unidade_orcamentaria_id: self.cota_orcamentaria.unidade_orcamentaria_id})
      .where(fonte_de_recursos_id: self.fonte_de_recursos_id)
      .sum(:valor).to_d
  end

  def saldo_a_distribuir
    self.valor - self.valor_distribuido - self.valor_setorial_distribuido
  end

  def valor_distribuido 
    self.doccs.sum(:valor)
  end

  def valor_setorial_distribuido
    self.propostas_orcamentarias_setoriais.sum(:valor)
  end

  def valor_distribuido_geral
    self.valor_distribuido + self.valor_setorial_distribuido
  end

  def gerar_doccs
    orcamentos_da_despesa = Loa::OrcamentoDaDespesa
      .joins(elemento_de_despesa_por_subacao: :subacao)
      .where(loa_subacoes: {unidade_orcamentaria_id: self.cota_orcamentaria.unidade_orcamentaria_id})
      .where(fonte_de_recursos_id: self.fonte_de_recursos_id).select { |i| ['31', '32', '46', '45'].include?(i.elemento_de_despesa_por_subacao.elemento_de_despesa.codigo[0..1]) }

    orcamentos_da_despesa.each do |orcamento_da_despesa|
      Loa::Docc.create(
        fonte_da_cota_orcamentaria: self,
        orcamento_da_despesa: orcamento_da_despesa,
        valor: 0
      )
    end
  end

  def gerar_propostas_orcamentarias_setoriais
    orcamentos_da_despesa = Loa::OrcamentoDaDespesa
      .joins(elemento_de_despesa_por_subacao: :subacao)
      .where(loa_subacoes: {unidade_orcamentaria_id: self.cota_orcamentaria.unidade_orcamentaria_id})
      .where(fonte_de_recursos_id: self.fonte_de_recursos_id).select { |i| !['31', '32', '46', '45'].include?(i.elemento_de_despesa_por_subacao.elemento_de_despesa.codigo[0..1]) }

    orcamentos_da_despesa.each do |orcamento_da_despesa|
      Loa::PropostaOrcamentariaSetorial.create(
        fonte_da_cota_orcamentaria: self,
        orcamento_da_despesa: orcamento_da_despesa,
        valor: 0
      )
    end
  end
end
