require 'active_support/concern'
require 'aasm'

module VistoriavelEmpenhosConcern
	extend ActiveSupport::Concern

	included do
		include AASM
		include MensagemConcern
		has_many :vistos, as: :vistoriavel, class_name: "Controladoria::Visto"

		aasm column: :status, enum: true, whiny_transitions: false do
			state :solicitado, :initial => true
			state :enviado_para_controladoria
			state :enviado_para_copfin
			state :enviado_para_contabilidade
			state :enviado_para_administrativo
			state :confirmado
			state :anulado
			state :recebido
			state :aguardando_alteracao_do_orcamento
			state :retornado_pela_controladoria
			state :retornado_pela_contabilidade

			event :enviar_para_controladoria, guard: :envia_pra_controladoria? do
				transitions from: :solicitado, to: :enviado_para_controladoria do
					guard do
						vistos.copfin.empty?
					end
				end

				transitions from: :retornado_pela_controladoria, to: :enviado_para_controladoria do
					guard do
						vistos.copfin.empty?
					end
				end

				after do
					update_column(:ultimo_envio_controladoria, Time.now)
				end
			end

			event :enviar_para_copfin, guard: :envia_pro_copfin? do
				transitions from: :solicitado, to: :enviado_para_copfin do
					guard do
						!envia_pra_controladoria? || reprovado_pelo_copfin? ||
							(aprovado_pelo_copfin? && vistos.copfin.last.created_at < updated_at)
					end
				end

				transitions from: :enviado_para_controladoria, to: :enviado_para_copfin do
					guard do
						aprovado_pela_controladoria? && vistos.copfin.empty?
					end
				end

				after do
					update_column(:ultimo_envio_copfin, Time.now)
				end
			end

			event :enviar_para_contabilidade, guard: :envia_pra_contabilidade? do
				transitions from: :solicitado, to: :enviado_para_contabilidade do
					guard do
						!envia_pra_controladoria? && !envia_pro_copfin? && definir_valor_do_empenho > 0 && ((definir_valor_do_empenho <= valor_restante_da_dotacao.to_f && Configuracao.last.valida_saldo_da_dotacao_no_empenho?) || !Configuracao.last.valida_saldo_da_dotacao_no_empenho?)
					end
				end

				transitions from: :retornado_pela_contabilidade, to: :enviado_para_contabilidade do
					guard do
						!envia_pra_controladoria? && !envia_pro_copfin? && definir_valor_do_empenho > 0 && ((definir_valor_do_empenho <= valor_restante_da_dotacao.to_f && Configuracao.last.valida_saldo_da_dotacao_no_empenho?) || !Configuracao.last.valida_saldo_da_dotacao_no_empenho?)
					end
				end

				transitions from: :enviado_para_controladoria, to: :enviado_para_contabilidade do
					guard do
						aprovado_pela_controladoria? && !envia_pro_copfin?
					end
				end

				transitions from: :enviado_para_copfin, to: :enviado_para_contabilidade do
					guard do
						aprovado_pelo_copfin?
					end
				end
			end

			event :retornar_para_administrativo do
				transitions from: :enviado_para_controladoria, to: :retornado_pela_controladoria, guard: :reprovado_pela_controladoria?
				transitions from: :enviado_para_copfin, to: :solicitado, guard: :reprovado_pelo_copfin?

				transitions from: :enviado_para_contabilidade, to: :retornado_pela_contabilidade do
					guard do
						existe_lote_do_sim? == false && envia_pra_contabilidade? && !recebido?
					end
				end

				transitions from: :recebido, to: :retornado_pela_contabilidade do
					guard do
						existe_lote_do_sim? == false && envia_pra_contabilidade? && !enviado_para_controladoria?
					end
				end
			end

			event :enviar_para_administrativo do
				transitions from: :enviado_para_controladoria, to: :enviado_para_administrativo do
					guard do
						existe_lote_do_sim? == false && aprovado_pela_controladoria? && !envia_pro_copfin? && !envia_pra_contabilidade?
					end
				end

				transitions from: :enviado_para_copfin, to: :enviado_para_administrativo do
					guard do
						existe_lote_do_sim? == false && aprovado_pelo_copfin? && !envia_pra_contabilidade?
					end
				end
			end

			event :receber do
				transitions from: :enviado_para_contabilidade, to: :recebido
			end

			event :confirmar, guard: :numero_configurado_e_empenho_tem_valor? do
				transitions from: :solicitado, to: :confirmado do
					guard do
						existe_lote_do_sim? == false && empenho_com_mesmo_numero.nil? &&
						(!Configuracao.last.valida_saldo_da_dotacao_no_empenho? || (Configuracao.last.valida_saldo_da_dotacao_no_empenho? &&
						dotacao_do_empenho_possui_saldo?)) && !envia_pra_controladoria? && !envia_pro_copfin? && (recebido? || solicitado?) &&
						numero_confirmado? && esta_de_acordo_com_parametrizacao_da_diaria? && (contexto_atual.exercicio == self.orcamento.exercicio)
					end
				end

				transitions from: :enviado_para_administrativo, to: :confirmado do
					guard do 
						existe_lote_do_sim? == false && empenho_com_mesmo_numero.nil? && esta_de_acordo_com_parametrizacao_da_diaria? && numero_confirmado?
					end
				end

				transitions from: :recebido, to: :confirmado do
					guard do 
						existe_lote_do_sim? == false && empenho_com_mesmo_numero.nil? && esta_de_acordo_com_parametrizacao_da_diaria? && numero_confirmado?
					end
				end

				transitions from: :aguardando_alteracao_do_orcamento, to: :confirmado do
					guard do
						existe_lote_do_sim? == false && empenho_com_mesmo_numero.nil? &&
						(!Configuracao.last.valida_saldo_da_dotacao_no_empenho? || (Configuracao.last.valida_saldo_da_dotacao_no_empenho? &&
						dotacao_do_empenho_possui_saldo?)) && numero_confirmado? && esta_de_acordo_com_parametrizacao_da_diaria?
					end
				end

				transitions from: :anulado, to: :confirmado do
					guard do
						!empenho_esta_anulado? && esta_de_acordo_com_parametrizacao_da_diaria? && numero_confirmado?
					end
				end

				after do
					cria_mensagem_empenho_confirmado
					if self.numero_do_empenho.blank?
						update_column(:numero_do_empenho, atribui_codigo_disponivel)
					end
				end
			end

			event :aguardar_alteracao_do_orcamento do
				transitions from: :confirmado, to: :aguardando_alteracao_do_orcamento
			end

			event :retornar_para_solicitado do
				transitions from: :confirmado, to: :solicitado
				transitions from: :confirmado, to: :enviado_para_contabilidade do
					after do
						atualiza_data_sim_do_contrato_aditivo_e_processo if Configuracao.last.faz_envio_do_sim? && self.contrato.present?
					end
				end
				
				transitions from: :confirmado, to: :enviado_para_contabilidade do
					after do
						atualiza_data_sim_do_contrato_aditivo_e_processo if Configuracao.last.faz_envio_do_sim? && self.contrato.present?
					end
				end
				
				transitions from: :enviado_para_administrativo, to: :solicitado

				after do
					apagar_movimento_orcamentario
					atualiza_data_sim_do_contrato_aditivo_e_processo if Configuracao.last.faz_envio_do_sim? && self.contrato.present?
					self.update(data_do_empenho: nil, numero_do_empenho: nil)
				end
			end

			event :anular do
				transitions from: :confirmado, to: :anulado do
					guard do
						empenho_esta_anulado?
					end
				end
			end
		end
	end

	# HELPER METHODS
	def envia_pra_controladoria?
		return Configuracao.last.envia_empenho_de_diaria_para_controladoria? if de_diaria?

		Configuracao.last.envia_empenho_para_controladoria?
	end

	def envia_pro_copfin?
		return Configuracao.last.envia_empenho_de_diaria_para_copfin? if de_diaria?

		Configuracao.last.envia_empenho_para_copfin?
	end

	def envia_pra_contabilidade?
		Configuracao.last.envia_empenho_para_contabilidade?
	end

	def aprovado_pela_controladoria?
		vistos = self.vistos.controladoria
		return (vistos.any? && vistos.last.aprovado?) if self.ultimo_envio_controladoria.nil?
		vistos.any? && vistos.last.aprovado? && self.ultimo_envio_controladoria < vistos.last.created_at
	end

	def aprovado_pelo_copfin?
		vistos = self.vistos.copfin
		return (vistos.any? && vistos.last.aprovado?) if ultimo_envio_copfin.nil?
		vistos.any? && vistos.last.aprovado? && ultimo_envio_copfin < vistos.last.created_at
	end

	def reprovado_pela_controladoria?
		vistos = self.vistos.controladoria
		return (vistos.any? && !vistos.last.aprovado?) if ultimo_envio_controladoria.nil?
		vistos.any? && !vistos.last.aprovado? && ultimo_envio_controladoria < vistos.last.created_at
	end

	def reprovado_pelo_copfin?
		vistos = self.vistos.copfin
		return (vistos.any? && !vistos.last.aprovado?) if ultimo_envio_copfin.nil?
		vistos.any? && !vistos.last.aprovado? && ultimo_envio_copfin < vistos.last.created_at
	end

	def pode_criar_mais_vistos?
		ultimo_envio =
			if ultimo_envio_controladoria && ultimo_envio_copfin
				ultimo_envio_controladoria >= ultimo_envio_copfin ? ultimo_envio_controladoria : ultimo_envio_copfin
			else
				ultimo_envio_copfin || ultimo_envio_controladoria || updated_at
			end

		self.vistos.empty? || self.vistos.last.created_at < ultimo_envio
	end

	def de_diaria?
		diaria.present?
	end

	def numero_configurado?
		# a pedido da Eduarda, por enquanto a contabilidade também vai poder configurar o número
		#return true unless Configuracao.last.configura_numero_do_empenho? && !Configuracao.last.envia_empenho_para_contabilidade?
		return true unless Configuracao.last.configura_numero_do_empenho?
		Configuracao.last.configura_numero_do_empenho? && self.numero_confirmado.present?
	end

	def empenho_esta_anulado?
		definir_valor_do_empenho.to_f == valor_anulado.to_f
	end

	def numero_do_empenho_configurado?
		self.numero_configurado?
	end

	def numero_configurado_e_empenho_tem_valor?
		self.numero_configurado? && self.definir_valor_do_empenho > 0
	end

	def esta_de_acordo_com_parametrizacao_da_diaria?
		configuracao = Configuracao.last
		return true if configuracao.envia_sim_contabilidade? == false || diaria? == false || configuracao.usa_modulo_contabil? == false

		configuracao.envia_sim_contabilidade? && diaria_id.present?
	end
end
