class Obra::OperacaoDeCredito < ApplicationRecord
	has_paper_trail

	include TradutorConcern

	attr_accessor :orgao_id
	attr_accessor :deducao
	attr_default :deducao, false

	belongs_to :obra, class_name: 'Contabilidade::Obra'
	belongs_to :unidade_orcamentaria, class_name: 'Loa::UnidadeOrcamentaria', required: true
	belongs_to :financiador, class_name: 'Base::Pessoa', foreign_key: "financiador_id", required: true
	belongs_to :funcao, class_name: 'Base::Funcao'
	belongs_to :natureza_da_receita, class_name: 'Base::NaturezaDaReceita'
	belongs_to :natureza_da_receita_aplicacao_fin, class_name: 'Base::NaturezaDaReceita', foreign_key: "natureza_da_receita_aplicacao_fin_id"
	belongs_to :conta_bancaria, class_name: "Base::ContaBancaria", required: true
	belongs_to :conta, class_name: 'Contabilidade::Conta', required: true
	belongs_to :unidade_orcamentaria_arrecadadora, class_name: 'Loa::UnidadeOrcamentaria', foreign_key: "unidade_orcamentaria_arrecadadora_id" , required: true
	belongs_to :conta_bancaria_arrecadadora, class_name: "Base::ContaBancaria", foreign_key: "conta_bancaria_arrecadadora_id", required: true
	belongs_to :sub_conta_pcasp, class_name: 'Contabilidade::SubContaPcasp'

	has_many :componentes_da_operacao_de_credito, class_name: "Obra::ComponenteDaOperacaoDeCredito", dependent: :destroy
	has_many :subcomponentes_da_operacao_de_credito, through: :componentes_da_operacao_de_credito
	has_many :acoes_do_componente, through: :subcomponentes_da_operacao_de_credito
	has_many :solicitacoes_de_alteracao_orcamentaria, class_name: "Contabilidade::SolicitacaoDeAlteracaoOrcamentaria"
	has_many :taloes_de_receita, class_name: 'Contabilidade::TalaoDeReceita'

	accepts_nested_attributes_for :componentes_da_operacao_de_credito, allow_destroy: true

	validates_presence_of :data, :inicio_da_vigencia, :fim_da_vigencia, :valor_operacao_credito, :conta_id

	validates_uniqueness_of :conta_bancaria

	validate :valida_valor_total
	validate :data_fim_da_vigencia_nao_pode_ser_anterior_a_data_de_inicio
	validate :data_de_inicio_nao_pode_ser_antes_ou_depois_da_obra

	validate :valor_da_operacao_de_credito_nao_pode_ser_menor_que_o_valor_dos_componentes
	before_validation :atribui_valor_total, if: Proc.new { self.valor_operacao_credito.present?}
	before_save :altera_status

	before_create :gera_codigo

	enum moeda: {
		real: 0,
		dolar: 1,
		euro: 2
	}

	enum periodicidade_amortizacao: {
		mensal: 0,
		semestral: 1,
		trimestral: 2,
		anual: 3
	}

	enum status: {
		pendente_finalizar_cadastro: 1,
		aguardando_inicio_da_execucao: 2,
		em_execucao: 3,
		executado: 4,
		expirado: 5
	}

	# VALIDAÇÕES
	def data_fim_da_vigencia_nao_pode_ser_anterior_a_data_de_inicio
		unless inicio_da_vigencia.nil? || fim_da_vigencia.nil?
			errors.add(:fim_da_vigencia, "deve ser maior que a data de início da vigência") if fim_da_vigencia < inicio_da_vigencia
		end
	end

	def codigo_subconta
		"#{self.codigo} / #{self.sub_conta_pcasp.try(:codigo_e_descricao)}"
	end

	def data_de_inicio_nao_pode_ser_antes_ou_depois_da_obra
		unless inicio_da_vigencia.nil? || obra.nil?
			errors.add(:inicio_da_vigencia, "deve ser maior ou igual a data de início da obra: #{obra.data_de_inicio}") if inicio_da_vigencia < obra.data_de_inicio
			errors.add(:inicio_da_vigencia, "deve ser menor ou igual a data de previsão de término da obra: #{obra.data_de_inicio}") if inicio_da_vigencia > obra.data_prevista_de_termino
		end
	end

	def altera_status
		# comentei essa parte do codigo, pois numa conversa com a Eduarda ela falou que não tinha todas aquelas obrigatoriedades de campos
		# if !cadastro_completo?
		# 	self.status = "pendente_finalizar_cadastro"
		
		if !esta_no_periodo_de_vigencia?
			self.status = "aguardando_inicio_da_execucao"
		elsif esta_no_periodo_de_vigencia? && !valor_da_conta_bancaria_zerou?
			self.status = "em_execucao"
		elsif passou_do_periodo_de_vigencia? && !valor_da_conta_bancaria_zerou?
			self.status = "expirado"
		elsif valor_da_conta_bancaria_zerou?
			self.status = "executado"
		end
	end

	def simbolo_monetario
		case self.moeda
		when "real"
			"R$"
		when "dolar"
			"$"
		when "euro"
			"€"
		else
			"R$"
		end
	end

	# VALORES
	def tempo_restante
		(self.fim_da_vigencia - Date.today).to_whole
	end

	def saldo_para_alteracao_orcamentaria
		self.valor_total.to_f - self.solicitacoes_de_alteracao_orcamentaria.sum(&:valor_a_suplementar).to_f
	end

	def porcentagem_do_saldo_vigencia
		diferenca = (Date.today - self.inicio_da_vigencia).to_i.to_whole
		porcentagem = (( diferenca * 100).to_f / (self.fim_da_vigencia - self.inicio_da_vigencia).to_whole).round(2)
		porcentagem.cap_at 100
	end

	def valor_total_dos_componentes
		total = componentes_da_operacao_de_credito.inject(0) { |total, componente_da_operacao_de_credito|
			total + componente_da_operacao_de_credito.valor_total_das_acoes.to_f
		}
	end

	def valor_da_operacao_de_credito_nao_pode_ser_menor_que_o_valor_dos_componentes
		errors.add(:base, "valor total da operação de crédito #{valor_total.try(:real_contabil)} não pode ser menor que o valor dos componentes #{valor_total_dos_componentes.try(:real_contabil)}") if valor_total_dos_componentes > valor_total.to_f
	end

	def percentual_de_execucao_pago
		if obra.present?
			valor_total_pago = obra.contas_bancarias_por_pagamento.joins(:pagamento).where(base_contas_bancarias_por_pagamento: {conta_bancaria_id: self.conta_bancaria_id}).sum("contabilidade_pagamentos.valor")
			porcentagem = self.valor_total == 0 ? 0 : ((valor_total_pago.to_f * 100).to_f / self.valor_total.to_f).round(2)
			porcentagem.cap_at 100
		else
			0
		end
	end

	def taloes_da_receita_por_conta_bancaria
		self.taloes_de_receita.joins(conta_bancaria_por_unidade_orcamentaria: :conta_bancaria).where(base_contas_bancarias: {id: self.conta_bancaria_id})
	end

	private

	def atribui_valor_total
		if self.valor_contrapartida.present?
			self.valor_total = self.valor_operacao_credito + self.valor_contrapartida
		else
			self.valor_total = self.valor_operacao_credito
		end
	end

	def valida_valor_total
		if self.valor_total && self.valor_operacao_credito && self.valor_contrapartida
			errors.add(:valor_total, "valor total deve ser igual a soma dos valores de op. de créd. e contrapartida") unless self.valor_total == (self.valor_operacao_credito + self.valor_contrapartida)
		end
	end

	def gera_codigo
		sequencial = (Obra::OperacaoDeCredito.count == 0) ? Obra::OperacaoDeCredito.count + 1 : Obra::OperacaoDeCredito.last.codigo[8..10].to_i + 1
		self.codigo = Date.today.year.to_s << unidade_orcamentaria.codigo_completo << sequencial.digitos(3) << ".OP"
	end

	def valor_total_dos_pagamentos_da_conta_bancaria_da_opercao_de_credito?
		total = self.conta_bancaria.contas_bancarias_por_pagamento.inject(0) { |total, conta_bancaria_por_pagamento|
			total + conta_bancaria_por_pagamento.valor_pago.to_f
		}
	end

	def cadastro_completo?
		self.moeda.present? && self.obra.present? && self.funcao.present? &&
		self.natureza_da_receita.present? && self.natureza_da_receita_aplicacao_fin.present? &&
		self.numero_do_contrato.present? && self.prazo_liberacao_execucao.present? &&
		self.prazo_carencia.present? && self.periodicidade_amortizacao.present?
	end

	def esta_no_periodo_de_vigencia?
		Date.today.between?(self.inicio_da_vigencia, self.fim_da_vigencia)
	end

	def passou_do_periodo_de_vigencia?
		Date.today > self.fim_da_vigencia
	end

	def valor_da_conta_bancaria_zerou?
		if self.valor_operacao_credito <= valor_total_dos_pagamentos_da_conta_bancaria_da_opercao_de_credito?
			return true
		else
			return false
		end
	end

end
