class Contabilidade::Convenio < ApplicationRecord

	# Esse cadastro não será usado. Será substituido por Obra::Transferencia (Convênio da Obra)

	has_paper_trail
	attr_accessor :contexto_atual_convenio
	attr_accessor :orgao_id

	belongs_to :orcamento, required: true
	belongs_to :funcao, class_name: 'Base::Funcao'
	belongs_to :tipo_de_transferencia, class_name: 'Base::TipoDeTransferencia'
	belongs_to :tipo_de_esfera, class_name: 'Base::TipoDeEsfera'
	belongs_to :unidade_orcamentaria, class_name: "Loa::UnidadeOrcamentaria"
	belongs_to :receita_corrente, class_name: "Base::NaturezaDaReceita", inverse_of: :convenios
	belongs_to :receita_de_capital, class_name: "Base::NaturezaDaReceita", inverse_of: :convenios
	belongs_to :convenio, class_name: "Ppa::Convenio"

	has_many :valores_do_convenio, class_name: 'Contabilidade::ValorDoConvenio', dependent: :destroy, inverse_of: :convenio
	has_many :convenios_contas_bancarias, dependent: :restrict_with_exception
	has_many :contas_bancarias, class_name: 'Base::ContaBancaria', through: :convenios_contas_bancarias



	accepts_nested_attributes_for :valores_do_convenio

	validates_associated :valores_do_convenio

	after_create :criar_valores_do_convenio_por_ano_do_orcamento_atual, unless: Proc.new { valores_do_convenio.present? }

	after_update :atualiza_calculo_por_exercicio_natureza_das_receitas, if: Proc.new { receita_corrente_id.present? || receita_de_capital_id.present? }

	before_destroy :atualiza_calculo_por_exercicio_natureza_das_receitas, if: Proc.new { receita_corrente_id.present? || receita_de_capital_id.present? }

	validates_presence_of :data_da_celebracao, :inicio_da_vigencia, :fim_da_vigencia, :funcao_id,
	:tipo_de_esfera_id, :modalidade, :tipo_de_transferencia_id, :valor_da_contrapartida, if: Proc.new{ |convenio| convenio.contexto_atual_convenio.eql? "Contabilidade" }

	validates_presence_of :receita_corrente_id, if: Proc.new { receita_de_capital_id.blank?} ,:message => 'No mínimo uma receita corrente ou de capital deve ser escolhida.'
	validates_presence_of :receita_de_capital_id, if: Proc.new { receita_corrente_id.blank?} ,:message => 'No mínimo uma receita corrente ou de capital deve ser escolhida.'
	validates_presence_of :unidade_orcamentaria_id, if: Proc.new { numero.present? || valor_da_contrapartida.present? }

	validates_uniqueness_of :numero, scope: :orcamento_id, if: Proc.new{ |convenio| convenio.numero.present? }

	validates :data_da_celebracao, date: true, if: Proc.new{ |convenio| convenio.contexto_atual_convenio.eql? "Contabilidade" }
	validates :inicio_da_vigencia, date: true, if: Proc.new{ |convenio| convenio.contexto_atual_convenio.eql? "Contabilidade" }
	validates :fim_da_vigencia, date: true, if: Proc.new{ |convenio| convenio.contexto_atual_convenio.eql? "Contabilidade" }

	validate :transferencia_deve_ser_concedida, if: Proc.new{ tipo_de_transferencia_id.present? && modalidade.present? }

	enum modalidade: {
		concedido: 0,
		recebido: 1
	}

	def ano_orcamento_e_numero
		"#{self.numero.digitos(4)}/#{orcamento.exercicio}" if self.numero
	end

	def nome_do_orgao
		self.unidade_orcamentaria.orgao.nome if self.unidade_orcamentaria
	end

	def sugestao_de_codigo_para_a_proxima_acao
		self.numero = Contabilidade::Convenio.maximum(:numero).to_i + 1
	end

	def valor_total
		valor_do_repasse.to_f + valor_da_contrapartida.to_f
	end

	def periodo
		"#{inicio_da_vigencia} - #{fim_da_vigencia}"
	end

	def total_para_primeiro_ano_do_exercicio
		self.valores_do_convenio.where(exercicio: self.orcamento.exercicio).sum(:valor).real_contabil
	end

	def transferencia_deve_ser_concedida
		if !modalidade.eql?("concedido") && tipo_de_transferencia.numero.eql?(5)
			errors.add(:modalidade, 'modalidade deve ser concedido para este tipo de transferência')
		elsif modalidade.eql?("concedido") && !tipo_de_transferencia.numero.eql?(5)
			errors.add(:tipo_de_transferencia_id, 'tipo deve ser transferências municipais concedidas para esta modalidade')
		end
	end

	def periodo_exercicio_orcamento_para_convenio orcamento_atual
		novo_periodo = orcamento_atual.exercicio + 2
		orcamento_atual.exercicio..novo_periodo
	end

	def importa_valores_do_convenio_por_ano_do_orcamento_atual_a_partir_do_ppa convenio_ppa
		if orcamento.present?
			periodo = orcamento.exercicio + 2
			despesa_corrente = Base::TipoDeDespesa.despesa_corrente
			despesa_de_capital = Base::TipoDeDespesa.despesa_de_capital

			(orcamento.exercicio..periodo).each do |exercicio|
				if despesa_corrente
					valor = convenio_ppa.valores_do_convenio.find_by(exercicio: exercicio, tipo_de_despesa_id: despesa_corrente.id).try(:valor) || 0
					importa_valor_do_convenio_ppa despesa_corrente.id, exercicio, valor
				end

				if despesa_de_capital
					valor = convenio_ppa.valores_do_convenio.find_by(exercicio: exercicio, tipo_de_despesa_id: despesa_de_capital.id).try(:valor) || 0
					importa_valor_do_convenio_ppa despesa_de_capital.id, exercicio, valor
				end
			end
		end
	end

	def importa_valor_do_convenio_ppa tipo_de_despesa, exercicio, valor
		Contabilidade::ValorDoConvenio.transaction do
			if tipo_de_despesa.present? && exercicio.present? && valor.present?
				valor_do_convenio = Contabilidade::ValorDoConvenio.find_by(convenio_id: id, tipo_de_despesa_id: tipo_de_despesa, exercicio: exercicio)
				if valor_do_convenio.present?
					valor_do_convenio.update(valor: valor)
				else
					criar_valor_do_convenio_orcamento tipo_de_despesa, exercicio, valor
				end
			else
				raise ActiveRecord::Rollback
			end
		end
	end

	def criar_valores_do_convenio_por_ano_do_orcamento_atual
		if orcamento.present?
			periodo = orcamento.exercicio + 2
			despesa_corrente = Base::TipoDeDespesa.despesa_corrente
			despesa_de_capital = Base::TipoDeDespesa.despesa_de_capital

			(orcamento.exercicio..periodo).each do |exercicio|
				valor = valores_do_convenio.find_by(exercicio: exercicio, tipo_de_despesa_id: despesa_corrente.id).try(:valor) || 0
				criar_valor_do_convenio_orcamento despesa_corrente.id, exercicio, valor

				valor = valores_do_convenio.find_by(exercicio: exercicio, tipo_de_despesa_id: despesa_de_capital.id).try(:valor) || 0
				criar_valor_do_convenio_orcamento despesa_de_capital.id, exercicio, valor
			end
		end
	end

	def criar_valor_do_convenio_orcamento tipo_de_despesa, exercicio, valor
		Contabilidade::ValorDoConvenio.transaction do
			if tipo_de_despesa.present? && exercicio.present? && valor.present?
				Contabilidade::ValorDoConvenio.create!(
					convenio_id: id,
					tipo_de_despesa_id: tipo_de_despesa,
					exercicio: exercicio,
					valor: valor
				)
			else
				raise ActiveRecord::Rollback
			end
		end
	end

	def atualiza_calculo_por_exercicio_natureza_das_receitas
		atualiza_valor_da_projecao_para_receita_corrente if receita_corrente.present?
		atualiza_valor_da_projecao_para_receita_de_capital if receita_de_capital.present?

		atualiza_valor_por_receita_corrente_alterado if receita_corrente_id_changed? && receita_corrente_id_was.present?
		atualiza_valor_por_receita_de_capital_alterado if receita_de_capital_id_changed? && receita_de_capital_id_was.present?
	end

	def atualiza_valor_da_projecao_para_receita_corrente
		unless receita_corrente.atualizar_valor_de_convenio
			errors.add(:receita_corrente_id, "Não foi possível atualizar cálculo para receita corrente")
		end
	end

	def atualiza_valor_da_projecao_para_receita_de_capital
		unless receita_de_capital.atualizar_valor_de_convenio
			errors.add(:receita_de_capital_id, "Não foi possível atualizar cálculo para receita de capital")
		end
	end

	def atualiza_valor_por_receita_de_capital_alterado
		receita_de_capital_antiga = Base::NaturezaDaReceita.find(receita_de_capital_id_was)
		errors.add(:receita_de_capital_id, "Não foi possível atualizar cálculo para receita de capital") unless receita_de_capital_antiga.atualizar_valor_de_convenio
	end

	def atualiza_valor_por_receita_corrente_alterado
		receita_corrente_antiga = Base::NaturezaDaReceita.find(receita_corrente_id_was)
		errors.add(:receita_de_capital_id, "Não foi possível atualizar cálculo para receita de capital") unless receita_corrente_antiga.atualizar_valor_de_convenio
	end

	def self.importa_convenios_para_orcamento convenios, orcamento_id
		mensagem = []
		receitas_nao_importadas = []

		convenios.each do |convenio|
			convenio_ppa = Ppa::Convenio.find(convenio)

			receita_corrente_antiga = convenio_ppa.receita_corrente.try(:codigo)
			receita_de_capital_antiga = convenio_ppa.receita_de_capital.try(:codigo)

			receita_corrente_tem_importacao = Base::NaturezaDaReceita.pesquisa_receita_nova_usando_receita_antiga receita_corrente_antiga, orcamento_id
			receita_de_capital_tem_importacao = Base::NaturezaDaReceita.pesquisa_receita_nova_usando_receita_antiga receita_de_capital_antiga, orcamento_id

			if (receita_corrente_tem_importacao && receita_corrente_tem_importacao.de_convenio) || (receita_de_capital_tem_importacao && receita_de_capital_tem_importacao.de_convenio)
				novo_convenio = cria_convenio_orcamento convenio_ppa, orcamento_id, receita_de_capital_antiga, receita_corrente_antiga
				novo_convenio.importa_valores_do_convenio_por_ano_do_orcamento_atual_a_partir_do_ppa(convenio_ppa) if novo_convenio.present?
				mensagem = {resultado: true}
			else
				receitas_nao_importadas << receita_corrente_antiga if receita_corrente_antiga
				receitas_nao_importadas << receita_de_capital_antiga if receita_de_capital_antiga

				mensagem = {resultado: false, msg: "Não é possível importar "}
				if receita_corrente_tem_importacao.try(:de_convenio).blank? || receita_de_capital_tem_importacao.try(:de_convenio).blank?
					mensagem[:msg] << " convênio(s) de código(s) #{receitas_nao_importadas.join(', ')} possuem receita(s) que não está marcada como de convênio."
				elsif receitas_nao_importadas.size > 1
					mensagem[:msg] << " seguintes convênios de códigos #{receitas_nao_importadas.join(', ')} possuem receitas que ainda não foram importados do STN para esse orçamento."
				else
					mensagem[:msg] << " seguinte convênio de código #{receitas_nao_importadas.join(', ')} possui uma receita que ainda não foi importada do STN para esse orçamento."
				end
			end
		end

		mensagem
	end

	def self.cria_convenio_orcamento convenio_ppa, orcamento_id, receita_de_capital_antiga, receita_corrente_antiga
		exercicio_orcamento = Orcamento.find(orcamento_id).exercicio

		if convenio_ppa.present? && orcamento_id.present?
			unless convenio_ja_foi_importado? convenio_ppa.id, orcamento_id
				if exercicio_orcamento >= 2018 && (receita_corrente_antiga || receita_de_capital_antiga)
					receita_corrente_nova = Base::NaturezaDaReceita.pesquisa_receita_nova_usando_receita_antiga receita_corrente_antiga, orcamento_id
					receita_de_capital_nova = Base::NaturezaDaReceita.pesquisa_receita_nova_usando_receita_antiga receita_de_capital_antiga, orcamento_id

					salva_novo_convenio convenio_ppa, receita_de_capital_nova, receita_corrente_nova, orcamento_id
				else
					salva_novo_convenio convenio_ppa, convenio_ppa.receita_de_capital_id, convenio_ppa.receita_corrente_id, orcamento_id
				end
			else
				raise ActiveRecord::Rollback
			end

		else
			raise ActiveRecord::Rollback
		end
	end

	def self.salva_novo_convenio convenio_ppa, receita_de_capital, receita_corrente, orcamento_id
		Contabilidade::Convenio.transaction do
			Contabilidade::Convenio.create!(
				orcamento_id: orcamento_id,
				numero: convenio_ppa.numero_do_convenio,
				descricao: convenio_ppa.objeto,
				receita_corrente_id: convenio_ppa.receita_corrente.try(:id),
				receita_de_capital_id: convenio_ppa.receita_de_capital.try(:id),
				convenio_id: convenio_ppa.id,
				unidade_orcamentaria_id: convenio_ppa.unidade_orcamentaria_id,
				tipo_de_esfera_id: convenio_ppa.esfera,
				cedente: convenio_ppa.concedente,
				funcao_id: convenio_ppa.sub_area_tematica.funcao_id
			)
		end
	end

	def self.convenio_ja_foi_importado? convenio_ppa, orcamento_id
		find_by(convenio_id: convenio_ppa, orcamento_id: orcamento_id).present?
	end

end
