class Contabilidade::SubElementoDeDespesa < ApplicationRecord
	has_paper_trail

	attr_default :vpd_obrigatorio, :false

	attr_accessor :topico_da_subconta

	
	belongs_to :elemento_de_despesa, class_name: 'Base::ElementoDeDespesa'
	belongs_to :elemento_de_gasto, class_name: "NaturezaDaDespesa::SubElementoDeDespesa"
	belongs_to :sub_conta_pcasp, class_name: "Contabilidade::SubContaPcasp", required: false
	belongs_to :sub_elemento_origem, class_name: "Contabilidade::SubElementoDeDespesa", foreign_key: :sub_elemento_origem_id, required: false
	belongs_to :sub_elemento_origem_tce, class_name: "NaturezaDaDespesa::SubElementoDeDespesa", foreign_key: :sub_elemento_origem_tce_id, required: false

	has_many :bloqueio_de_dotacoes, class_name: "Contabilidade::BloqueioDeDotacao", dependent: :restrict_with_exception
	has_many :empenhos, class_name: "Contabilidade::Empenho", dependent: :restrict_with_exception
	has_many :liquidacoes, through: :empenhos, class_name: "Contabilidade::Liquidacao"
	has_many :pagamentos, through: :liquidacoes, class_name: "Contabilidade::Pagamento"
	has_many :orcamentos_da_despesa_por_diaria, class_name: "Contabilidade::OrcamentoDaDespesaPorDiaria", dependent: :restrict_with_exception
	has_many :orcamentos_da_despesa_por_evento_contabil, class_name: "Contabilidade::OrcamentoDaDespesaPorEventoContabil", dependent: :restrict_with_exception
	has_many :orcamentos_da_despesa_do_apostilamento, class_name: "Licitacao::OrcamentoDaDespesaDoApostilamento", dependent: :restrict_with_exception
	has_many :orcamentos_da_despesa_do_aditivo, class_name: "Licitacao::OrcamentoDaDespesaDoAditivo", dependent: :restrict_with_exception
	has_many :orcamentos_da_despesa_do_contrato, class_name: "Licitacao::OrcamentoDaDespesaDoContrato", dependent: :restrict_with_exception
	has_many :orcamentos_da_despesa_por_projeto, class_name: "Licitacao::OrcamentoDaDespesaPorProjeto", dependent: :restrict_with_exception
	has_many :orcamentos_da_despesa_por_acao, class_name: "Pca::OrcamentoDaDespesaPorAcao",  dependent: :restrict_with_exception
	has_many :orcamentos_da_despesa_por_pedido, class_name: "Licitacao::OrcamentoDaDespesaPorPedido", dependent: :restrict_with_exception
	has_many :estoques, class_name: "GestaoDeEstoque::Estoque"
	has_many :sub_elementos_de_despesa_da_configuracao_contabil, class_name: "Contabilidade::SubElementoDeDespesaDaConfiguracaoContabil"

	validates_presence_of :codigo, :descricao, :elemento_de_despesa_id

	validates_uniqueness_of :codigo, scope: :elemento_de_despesa_id, case_sensitive: false, conditions: -> { where(elemento_de_gasto_id: '') }
	validates_uniqueness_of :descricao, scope: :elemento_de_despesa_id, case_sensitive: false, conditions: -> { where(elemento_de_gasto_id: '') }
	validates_uniqueness_of :codigo, scope: [:elemento_de_despesa_id, :elemento_de_gasto_id], case_sensitive: false, conditions: -> { where.not(elemento_de_gasto_id: '') }
	validates_uniqueness_of :descricao, scope: [:elemento_de_despesa_id, :elemento_de_gasto_id], case_sensitive: false, conditions: -> { where.not(elemento_de_gasto_id: '') }

	validate :valida_quantidade_de_digitos, on: :create

	after_initialize :popula_topico_da_subconta

	scope :ativos, -> { where('contabilidade_sub_elementos_de_despesa.inativo is not TRUE') }

	enum uso_na_msc: {
		usar: 1,
		usar_elemento: 2,
		usar_sub_elemento_99: 3,
		usar_modalidade_de_aplicacao: 4
	}

	# VALORES
	def codigo_formatado_e_descricao
		"#{codigo_formatado} - #{descricao}"
	end

	def codigo_e_descricao
		"#{self.codigo} - #{self.descricao}"
	end

	def grupo_de_natureza_da_despesa
		codigo_completo[0, 2] + '000000'
	end

	def categoria_economica
		codigo_completo[0, 1] + '0000000'
	end

	def codigo_completo
		"#{elemento_de_despesa.codigo[0..5]}#{self.codigo}"
	end

	def variante_do_codigo_completo
		"#{elemento_de_despesa.codigo[0..7]}#{self.codigo}"
	end

	def codigo_formatado
		codigo_completo.gsub(/(\d{1})(\d{1})(\d{2})(\d{2})(\d{2})/, '\1.\2.\3.\4.\5')
	end

	def variante_do_codigo_formatado
		variante_do_codigo_completo.gsub(/(\d{1})(\d{1})(\d{2})(\d{2})(\d{2})(\d{2})/, '\1.\2.\3.\4.\5\ \6')
	end

	def codigo_formatado_e_descricao
		"#{self.codigo_formatado} - #{self.descricao}"
	end

	def popula_topico_da_subconta
		if self.sub_conta_pcasp.present?
			self.topico_da_subconta = self.sub_conta_pcasp.topico_da_conta
		end
	end

	def valor_empenhado_por_unidades(unidades_orcamentarias_ids, data_inicial, data_final)
		@valor_empenhado_por_unidades ||= empenhos.joins([orcamento_da_despesa: [elemento_de_despesa_por_subacao: [:elemento_de_despesa, subacao: [:unidade_orcamentaria]]]]).where(
			"loa_unidades_orcamentarias.id IN(?) AND
			contabilidade_empenhos.data_do_empenho >= ? AND
			contabilidade_empenhos.data_do_empenho <= ?", unidades_orcamentarias_ids, data_inicial, data_final
		).sum(&:definir_valor_do_empenho)
	end

	def valor_empenhado_por_unidade(unidade_orcamentaria_id, data_final)
		@valor_empenhado_por_unidade ||= empenhos.joins([orcamento_da_despesa: [elemento_de_despesa_por_subacao: [:elemento_de_despesa, subacao: [:unidade_orcamentaria]]]])
			.where('loa_unidades_orcamentarias.id = ? AND contabilidade_empenhos.data_do_empenho <= ?', unidade_orcamentaria_id, data_final)
			.sum(&:definir_valor_do_empenho)
	end

	def valor_anulado_por_empenho(data_final)
		@valor_anulado_por_empenho ||= empenhos.joins("LEFT JOIN contabilidade_anulacoes_do_empenho ON contabilidade_anulacoes_do_empenho.empenho_id = contabilidade_empenhos.id")
			.where('contabilidade_anulacoes_do_empenho.data_da_anulacao <= ? AND contabilidade_anulacoes_do_empenho.empenho_id IS NOT NULL', data_final)
			.sum('contabilidade_anulacoes_do_empenho.valor')
	end

	def valor_liquidado_por_unidades(unidades_orcamentarias_ids, data_inicial, data_final)
		@valor_liquidado_por_unidades ||= liquidacoes.joins([empenho: [orcamento_da_despesa: [elemento_de_despesa_por_subacao: [:elemento_de_despesa, subacao: [:unidade_orcamentaria]]]]]).where(
			"loa_unidades_orcamentarias.id IN(?) AND
			contabilidade_liquidacoes.data_da_liquidacao >= ? AND
			contabilidade_liquidacoes.data_da_liquidacao <= ?", unidades_orcamentarias_ids, data_inicial, data_final
		).sum(:valor)
	end

	def valor_pago_por_unidades(unidades_orcamentarias_ids, data_inicial, data_final)
		@valor_pago_por_unidades ||= pagamentos.joins([liquidacao: [empenho: [orcamento_da_despesa: [elemento_de_despesa_por_subacao: [:elemento_de_despesa, subacao: [:unidade_orcamentaria]]]]]]).where(
			"loa_unidades_orcamentarias.id IN(?) AND
			contabilidade_pagamentos.data >= ? AND
			contabilidade_pagamentos.data <= ?", unidades_orcamentarias_ids, data_inicial, data_final
		).sum(:valor)
	end

	def valida_quantidade_de_digitos
		unless self.codigo.size == 2
			errors.add(:codigo, "deve possuir dois digitos incluindo os zeros a esquerda.")
		end
	end

	def codigo_do_objeto_para_msc
		if self.usar?
			self.codigo_completo
		elsif self.usar_elemento?
			self.elemento_de_despesa.codigo
		elsif self.usar_sub_elemento_99?
			sub_elemento_99 = self.elemento_de_despesa.sub_elementos_de_despesa.where(codigo: '99').first
			if sub_elemento_99.present?
				sub_elemento_99.codigo_completo
			else
				""
			end
		elsif self.usar_modalidade_de_aplicacao?
			self.elemento_de_despesa&.modalidade_de_aplicacao&.codigo
		end
	end
end
