require 'active_support/concern'
require 'aasm'

module VistoriavelLiquidacoesConcern
	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_administrativo
			state :enviado_para_contabilidade
			state :recebido
			state :enviado_para_o_financeiro
			state :recebido_pelo_financeiro
			state :confirmado
			state :autorizado
			state :retornado_pela_contabilidade
			state :retornado_pela_controladoria
			state :enviado_ao_email
			state :aguardando_notas_fiscais
			

			event :enviar_para_controladoria, guard: :envia_pra_controladoria? do
				transitions from: :solicitado, to: :enviado_para_controladoria do
					guard do 
						existe_lote_do_sim? == false && fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end
				end
				transitions from: :retornado_pela_controladoria, to: :enviado_para_controladoria do
					guard do 
						existe_lote_do_sim? == false && fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end
				end
			end

			event :retornar_para_administrativo do
				transitions from: :enviado_para_controladoria, to: :retornado_pela_controladoria do
					guard do
						reprovado_pela_controladoria?
					end
				end

				transitions from: :enviado_para_contabilidade, to: :retornado_pela_contabilidade
			end

			event :enviar_para_contabilidade, guard: :envia_pra_contabilidade? do
				transitions from: :solicitado, to: :enviado_para_contabilidade do
					guard do
						existe_lote_do_sim? == false && !envia_pra_controladoria?
					end
				end

				transitions from: :retornado_pela_contabilidade, to: :enviado_para_contabilidade do
					guard do
						envia_pra_controladoria? == false && fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end
				end

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

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

			event :enviar_para_o_financeiro, guard: :existem_itens? do
				# FLUXO NORMAL
				transitions from: :confirmado, to: :enviado_para_o_financeiro do
					guard do
						existe_lote_do_sim? == false && !self.nota_fiscal_a_preencher? && saldo.to_f > 0 && fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end
				end

				# FLUXO DE MULTIPLAS LIQUIDAÇÕES
				transitions from: :confirmado, to: :enviado_para_o_financeiro do 
					guard do 
						de_multiplas_notas_fiscais? && pagamentos_das_liquidacoes_filhas.empty? && liquidacoes_filhas_validas?
					end

					after do
						liquidacoes_filhas.update_all(status: Contabilidade::Liquidacao.status[:enviado_para_o_financeiro])
					end
				end
			end

			event :receber_pelo_financeiro do
				transitions from: :enviado_para_o_financeiro, to: :recebido_pelo_financeiro
			end

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

			event :confirmar, guard: :checa_valor_dos_itens do
				transitions from: :aguardando_notas_fiscais, to: :confirmado do
					guard do 
						de_multiplas_notas_fiscais? && liquidacoes_filhas_validas? && valor == valor_liquidacoes_filhas && fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end

					after do
						liquidacoes_filhas.update_all(status: Contabilidade::Liquidacao.status[:confirmado], data_da_liquidacao: Date.today)
					end
				end

				transitions from: :solicitado, to: :confirmado do
					guard do
						# de_multiplas_notas_fiscais se repete como condição por conta do teste se está logado na contabilidade
						(de_multiplas_notas_fiscais? == false || (de_multiplas_notas_fiscais? && todas_as_liquidacoes_filhas_possuem_itens? && valor == valor_liquidacoes_filhas && quantidade_de_liquidacoes_filhas_diferente_de_um?)) && existe_lote_do_sim? == false && fornecedor_de_a_cordo_com_o_tipo_da_nota? && !envia_pra_controladoria? && (!envia_pra_contabilidade? || (envia_pra_contabilidade? && criado_na_contabilidade?)) && (!logado_na_contabilidade || (de_multiplas_notas_fiscais? == false && !nota_fiscal_a_preencher?) || (de_multiplas_notas_fiscais? && todas_as_liquidacoes_filhas_possuem_itens? && valor == valor_liquidacoes_filhas && quantidade_de_liquidacoes_filhas_diferente_de_um?)) && mes_bloqueado? == false
					end

					after do
						liquidacoes_filhas.update_all(status: Contabilidade::Liquidacao.status[:confirmado], data_da_liquidacao: Date.today) if de_multiplas_notas_fiscais?
					end
				end

				transitions from: :enviado_para_administrativo, to: :confirmado do 
					guard do 
						existe_lote_do_sim? == false && fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end
				end

				transitions from: :enviado_para_o_financeiro, to: :confirmado do
					guard do 
						existe_lote_do_sim? == false && fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end
				end

				transitions from: :recebido_pelo_financeiro, to: :confirmado do
					guard do 
						existe_lote_do_sim? == false && fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end
				end

				transitions from: :recebido, to: :confirmado do
					guard do
						(!logado_na_contabilidade || !nota_fiscal_a_preencher?) && existe_lote_do_sim? == false && fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end
				end

				after do
					cria_mensagem_liquidacao_confirmada

					gera_linhas_dos_dependentes
				end
			end

			event :retornar_para_solicitado do
				transitions from: :confirmado, to: :solicitado do
					guard do
						!possui_pagamentos? && !envia_pra_contabilidade? && !estornada? && !enviado_ao_sim? && !mes_bloqueado?
					end

					after do
						self.update(data_da_liquidacao: nil)
						self.update_columns(
							controle_cronologico: false,
							previsao_de_pagamento: nil
						)
						self.movimentacoes_do_plano_de_contas.destroy_all
					end
				end

				transitions from: :confirmado, to: :enviado_para_contabilidade do
					guard do
						!possui_pagamentos? && envia_pra_contabilidade? && !estornada?
					end

					after do
						self.movimentacoes_do_plano_de_contas.destroy_all
					end
				end
			end

			event :autorizar do
				transitions from: :recebido_pelo_financeiro, to: :autorizado
				transitions from: :enviado_ao_email, to: :autorizado
			end

			event :enviar_ao_email do 
				transitions from: :recebido_pelo_financeiro, to: :enviado_ao_email
			end

			event :retornar_para_recebido do
				transitions from: :autorizado, to: :recebido_pelo_financeiro do
					guard do
						!possui_pagamentos? && !enviado_ao_sim?
					end
				end
			end

			event :retornar_para_confirmado do
				transitions from: :recebido_pelo_financeiro, to: :confirmado do
					guard do
						fornecedor_de_a_cordo_com_o_tipo_da_nota?
					end
				end
			end

			event :aguardar_notas_fiscais do 
				transitions from: :solicitado, to: :aguardando_notas_fiscais do 
					guard do 
						de_multiplas_notas_fiscais? && liquidacao_mae_id.nil? && !envia_pra_controladoria? && !envia_pra_contabilidade?
					end
				end

				transitions from: :recebido, to: :aguardando_notas_fiscais do 
					guard do
						de_multiplas_notas_fiscais? && liquidacao_mae_id.nil?
					end
				end

				transitions from: :enviado_para_administrativo, to: :aguardando_notas_fiscais do
					guard do 
						de_multiplas_notas_fiscais? && liquidacao_mae_id.nil?
					end
				end
			end
		end
	end

	# HELPER METHODS
	def envia_pra_controladoria?
		return Configuracao.last.envia_empenho_de_diaria_para_controladoria? if empenho_de_diaria?
		Configuracao.last.envia_liquidacao_para_controladoria?
	end

	def envia_pro_copfin?
		return Configuracao.last.envia_empenho_de_diaria_para_copfin? if empenho_de_diaria?
		Configuracao.last.envia_empenho_para_copfin?
	end

	def envia_pra_contabilidade?
		Configuracao.last.envia_liquidacao_para_contabilidade?
	end

	def aprovado_pela_controladoria?
		self.vistos.any? && self.vistos.last.aprovado? && updated_at < self.vistos.last.created_at
	end

	def reprovado_pela_controladoria?
		self.vistos.any? && !self.vistos.order(:id).last.aprovado?
	end

	def pode_criar_mais_vistos?
		enviado_para_controladoria? && (self.vistos.empty? || self.vistos.last.created_at < updated_at)
	end

	def checa_valor_dos_itens
		(existem_itens? && total_dos_itens_fecha_com_liquidacao?) || mae?
	end

	def empenho_de_diaria?
		empenho.diaria.present?
	end
end
