class Contabilidade::EventoContabil < ApplicationRecord
	include TradutorConcern
	include IncrementadorDeCodigoConcern
	has_paper_trail

	attr_default :fixo, false
	attr_default :padrao, false
	attr_default :tipo, :automatico
	attr_default :ativo, true

	attr_accessor :acao_do_sistema_hidden, :lancado_por_formulario

	belongs_to :acao_do_sistema
	belongs_to :orcamento
	belongs_to :grupo_de_evento_contabil, class_name: 'Contabilidade::GrupoDeEventoContabil'
	belongs_to :importacao_de_evento_contabil, class_name: 'Contabilidade::ImportacaoDeEventoContabil'

	has_one :configuracao_do_evento_contabil

	has_many :contas_por_eventos_contabeis, class_name:'Contabilidade::ContaPorEventoContabil', dependent: :destroy
	has_many :movimentacoes_do_plano_de_contas, through: :contas_por_eventos_contabeis
	has_many :orcamentos_da_despesa_por_evento_contabil, class_name: 'Contabilidade::OrcamentoDaDespesaPorEventoContabil', dependent: :destroy
	has_many :orcamentos_da_receita_por_evento_contabil, class_name: 'Contabilidade::OrcamentoDaReceitaPorEventoContabil', dependent: :destroy
	has_many :naturezas_da_receita_da_configuracao_contabil, through: :configuracao_do_evento_contabil
	has_many :fontes_da_configuracao_contabil, through: :configuracao_do_evento_contabil
	has_many :contas, through: :contas_por_eventos_contabeis


	accepts_nested_attributes_for :contas_por_eventos_contabeis, reject_if: :all_blank, allow_destroy: true

	validates_presence_of :nome, :orcamento_id, :tipo, :classe
	validates_presence_of :grupo_de_evento_contabil_id, if: proc {self.manual? and !self.lancado_por_formulario.present?}
	validates :ativo, inclusion: [true, false]
	validates_presence_of :modelo

	validates :orcamento_id, immutable: true

	before_validation :atribui_sequencial_disponivel, if: Proc.new {self.sequencial.nil? && self.orcamento.present?}

	after_destroy :deleta_configuracao

	enum tipo: {
		automatico: 0,
		semi_automatico: 1,
		manual: 2
		#estorno_automatico: 3,
		#estorno_semi_automatico: 4,
		#estorno_manual: 5
	}

	enum classe: {
		previsao_de_receita: 10,
		fixacao_da_despesa: 20,
		movimentacao_do_credito_orcamentario: 30,
		execucao_orcamentaria: 40,
		rotinas_automaticas_de_encerramento: 50,
		apropriacoes_de_vpd: 51,
		retencoes_e_registros_de_obrigacoes: 52,
		liquidacoes_e_baixa_de_obrigacoes: 53,
		execucao_orcamentaria_da_receita: 54,
		apropriacoes_de_bens_e_direitos: 55,
		liquidacoes_e_baixa_de_bens_e_direitos: 56,
		registros_diversos: 59,
		baixas_das_variacoes_patrimoniais_dim_vpd: 61,
		transferencias_sem_execucao_orcamentaria: 70,
		classificacoes_de_receitas_e_ingressos_sem_exec_orc: 80,
		controle: 90,
		transferencia_de_saldo: 99
	}

	enum tipo_de_fornecedor: {
		pessoa_fisica: 0,
		pessoa_juridica: 1
	}

	enum classificacao_tipo_de_material: {
		material_de_expediente: 0,
		material_de_consumo: 1,
		generos_alimenticios: 2,
		materiais_de_construcao: 3,
		autopecas: 4,
		medicamentos_e_materiais_hospitalares: 5,
		materiais_graficos: 6
	}

	enum modelo: {
		empenho: 1,
		liquidacao: 2,
		pagamento: 3,
		anulacao_do_empenho: 4,
		obra: 5,
		estorno_de_pagamento: 6,
		recebimento_de_material: 7,
		requisicao_de_material: 8,
		encerramento: 9,
		dotacao: 11,
		contrato: 12,
		ppa: 13,
		ploa: 14,
		talao_de_receita: 15,
		abertura: 16,
		retencao_de_pagamento: 17,
		despesa_extra_orcamentaria: 18,
		cancelamento_de_resto_a_pagar: 19,
		orcamento: 20,
		reconhecimento_programado: 21,
		intermodulo: 22,
		projecao_de_despesa: 23,
		receita: 24,
		loa: 25,
		orcamento_da_despesa: 26,
		orcamento_da_receita: 27,
		receita_stn: 28,
		medicao_da_obra: 29,
		bem_do_balancete: 30,
		almoxarifado: 31,
		patrimonio: 32,
		provisao: 33,
		reversao_de_provisao: 34,
		anulacao_do_talao_de_receita: 35,
		estorno_de_despesa_extra_orcamentaria: 36,
		evento_manual: 37,
		retencao: 38,
		previsao_da_receita: 39,
		situacao_da_obra: 40,
		item_do_consumo: 41,
		transferencia_financeira: 99,
		bloqueio_de_dotacao: 94,
		solicitacao_de_alteracao_orcamentaria: 95,
		estorno_de_liquidacao: 96,
		reconhecido_na_liquidacao_da_despesa: 320,
		reconhecimento_pelo_controle_de_consumo: 321,
		reconhecimento_eventual: 323,
		reconhecido_antes_da_liquidacao_nesse_exercicio: 324,
		reconhecido_antes_da_liquidacao_exercicio_anterior: 325,
		reconhecimento_no_exercicio_vigente: 326,
		reconhecimento_no_exercicio_anterior: 327,
		operacao_de_credito: 730,
		aditivo: 901,
		ddr: 998,
		transferencia_de_saldo_pcasp: 999
	}

	ransacker :detalhamento do
		Arel.sql("contabilidade_eventos_contabeis.classe::text ||'.'|| contabilidade_eventos_contabeis.tipo::text ||'.'|| LPAD(contabilidade_eventos_contabeis.sequencial::text, 3, '0')")
	end

	def self.descricao_do_tipo tipo = self.tipo
		Contabilidade::EventoContabil.tipos[tipo].to_s + " - " + Contabilidade::EventoContabil.localizar("tipo", tipo)
	end

	def self.descricao_da_classe classe = self.classe
		Contabilidade::EventoContabil.classes[classe].to_s + " - " + Contabilidade::EventoContabil.localizar("classe", classe)
	end

	def self.descricao_de_modelo modelo = self.classe
		Contabilidade::EventoContabil.localizar("modelo", modelo)
	end

	def detalhamento
		"#{Contabilidade::EventoContabil.classes[self.classe].to_s}.#{Contabilidade::EventoContabil.tipos[self.tipo].to_s}.#{sequencial.to_s}" if self.classe && self.tipo
	end

	def detalhamento_e_nome
		"#{detalhamento} - #{nome}"
	end

	def pares_de_contas
		return self.contas_por_eventos_contabeis.each_slice(2)
	end

	def pode_editar_acao?
		movimentacoes_do_plano_de_contas.empty?
	end

	def pode_adicionar_dotacoes?
		(self.apropriacoes_de_vpd? || self.retencoes_e_registros_de_obrigacoes? || self.apropriacoes_de_bens_e_direitos? || self.registros_diversos? || self.execucao_orcamentaria? || self.controle?) && self.automatico?
	end

	def pode_adicionar_receitas?
		self.execucao_orcamentaria_da_receita? && self.automatico?
	end

	def valida_dotacoes_despesa
		if pode_adicionar_dotacoes? && orcamentos_da_despesa_por_evento_contabil.blank?
			raise "Não existem dotações de depesa para o evento " << " (id: " << "#{self.id.to_s})"
		end
	end

	def valida_receitas
		if pode_adicionar_receitas? && orcamentos_da_receita_por_evento_contabil.blank?
			raise "Não existem receitas para o evento: " << " (id: " << "#{self.id.to_s})"
		end
	end

	def deleta_configuracao
		self.configuracao_do_evento_contabil.destroy if self.configuracao_do_evento_contabil.present?
	end

	def possui_dotacoes?
		self.configuracao_do_evento_contabil.present? && self.configuracao_do_evento_contabil.sub_elementos_de_despesa_da_configuracao_contabil.any?
	end

	def possui_fontes?
		self.configuracao_do_evento_contabil.present? && self.configuracao_do_evento_contabil.fontes_da_configuracao_contabil.any?
	end

	def pode_destruir?
		self.class.reflect_on_all_associations.all? do |nested|
			nested.options[:dependent] != :restrict_with_exception ||
        (nested.macro == :has_one && self.send(nested.name).nil?) ||
        (nested.macro == :has_many && self.send(nested.name).empty?)
		end
	end

	def total_movimentado
		self.movimentacoes_do_plano_de_contas.joins(:conta_por_evento_contabil).where(contabilidade_contas_por_eventos_contabeis: {tipo_de_lancamento: 0} ).distinct.sum(&:valor)
	end

	def total_movimentado_real_contabil
		self.total_movimentado.to_d.real_contabil
	end

	def codigo_da_conta_credito
		return self.contas_por_eventos_contabeis.find_by(tipo_de_lancamento: Contabilidade::ContaPorEventoContabil.tipo_de_lancamentos[:credito]).conta.codigo_formatado
	end

	def codigo_da_conta_debito
		self.contas_por_eventos_contabeis.find_by(tipo_de_lancamento: Contabilidade::ContaPorEventoContabil.tipo_de_lancamentos[:debito]).conta.codigo_formatado
	end

	def contem_conta_patrimonial?
		self.contas_por_eventos_contabeis.any? do |conta_por_evento_contabil|
			conta_por_evento_contabil.conta.grupo_de_conta.patrimonial? rescue false
		end
	end

	def campos_por_modelo_de_ativacao
		case modelo
		when 'empenho'
			%i[tipo_de_evento status modulo_de_ativacao modalidade_do_empenho empenho_complementar tipo_de_pessoa fluxo_completo_do_empenho tipo_de_resto_a_pagar uso_do_bem]
		when 'liquidacao'
			%i[tipo_de_evento status modulo_de_ativacao modalidade_do_empenho resto_a_pagar tipo_de_resto_a_pagar tipo_de_pessoa]
		when 'pagamento'
			%i[tipo_de_evento resto_a_pagar status processado conta_pcasp_da_conta_bancaria_id modalidade_do_empenho tipo_de_pessoa originado_de_um_evento_manual conta_pcasp_do_lancamento_manual_id tipo_de_resto_a_pagar]
		when 'estorno_de_pagamento'
			%i[tipo_de_evento resto_a_pagar processado conta_pcasp_da_conta_bancaria_id]
		when 'recebimento_de_material'
			%i[tipo_de_evento status modulo_de_ativacao modalidade_do_empenho recebimento_com_classificacao veio_de_uma_ordem resto_a_pagar]
		when 'planejamento'
			%i[tipo_de_evento status modulo_de_ativacao]
		when 'ppa'
			%i[tipo_de_evento status modulo_de_ativacao]
		when 'projecao_de_despesa'
			%i[tipo_de_evento status modulo_de_ativacao alteracao_no_saldo]
		when 'receita'
			%i[tipo_de_evento status modulo_de_ativacao alteracao_no_saldo]
		when 'orcamento_da_despesa'
			%i[tipo_de_evento status modulo_de_ativacao alteracao_no_saldo]
		when 'talao_de_receita'
			%i[tipo_de_evento receita_de_deducao status conta_pcasp_da_conta_bancaria_id extraorcamentario tipo_de_pessoa conta_pcasp com_fonte_de_recursos]
		when 'anulacao_do_talao_de_receita'
			%i[tipo_de_evento receita_de_deducao status conta_pcasp_da_conta_bancaria_id extraorcamentario tipo_de_pessoa]
		when 'medicao_da_obra'
			%i[status modulo_de_ativacao tipo_de_evento classificacao_da_obra modalidade_do_empenho tipo_de_obra tipo_de_pessoa resto_a_pagar]
		when 'anulacao_do_empenho'
			%i[status modulo_de_ativacao tipo_de_evento modalidade_do_empenho fluxo_completo_da_anulacao_do_empenho cancelamento_por_falta_de_disponibilidade_de_caixa]
		when 'bem_do_balancete'
			%i[bem_lancado modulo_de_ativacao tipo_do_imovel uso_do_bem]
		when 'obra'
			%i[obra_tombada modulo_de_ativacao tipo_do_bem_da_obra classificacao_da_obra uso_do_bem]
		when 'requisicao_de_material'
			%i[tipo_de_evento status modulo_de_ativacao veio_de_uma_ordem]
		when 'despesa_extra_orcamentaria'
			%i[tipo_de_evento conta_pcasp_da_conta_bancaria_id extraorcamentario]
		when 'estorno_de_despesa_extra_orcamentaria'
			%i[tipo_de_evento conta_pcasp_da_conta_bancaria_id extraorcamentario]
		when 'retencao'
			%i[tipo_de_evento conta_pcasp_id origem_da_retencao modalidade_do_empenho tipo_de_pessoa]
		when 'estorno_de_liquidacao'
			%i[status]
		when 'solicitacao_de_alteracao_orcamentaria'
			%i[status tipo_de_credito origem_do_recurso]
		when 'cancelamento_de_resto_a_pagar'
			%i[status tipo_de_credito origem_do_recurso tipo_de_resto_a_pagar motivo_cancelamento]
		when 'contrato'
			%i[status tipo_de_evento]
		else 
			[]
		end
	end

	private

	def atribui_sequencial_disponivel
		gerar_sugestao_codigo(:sequencial, 3, {orcamento_id: orcamento.id, classe: self.classe})
	end

end
