class Licitacao::AtaDeRegistroDePrecos < ApplicationRecord
	include AASM
	include MensagemConcern

	has_paper_trail

	attr_default :status, :aberto

	belongs_to :processo, class_name: "Licitacao::Processo", foreign_key: :projeto_id, required: true
	belongs_to :modelo_de_documento, foreign_key: :modelo_do_documento_id

	has_many :unidades_orcamentarias_da_ata, class_name: 'Licitacao::UnidadeOrcamentariaDaAta', foreign_key: :ata_de_registro_de_preco_id, dependent: :destroy
	has_many :unidades_orcamentarias, :through => :unidades_orcamentarias_da_ata
	has_many :contratos, class_name: "Licitacao::Contrato", foreign_key: :ata_de_registro_de_preco_id, dependent: :restrict_with_exception
	has_many :itens_dos_contratos, through: :contratos, source: 'itens_do_contrato', class_name: 'Licitacao::ItemDoContrato'
	has_many :itens_dos_lotes, through: :itens_dos_contratos, source: 'item_do_lote', class_name: 'Licitacao::ItemDoLote'
	has_many :itens_da_ata, class_name: "Licitacao::ItemDaAta", foreign_key: :ata_de_registro_de_preco_id, dependent: :destroy
	has_many :itens_do_lote_da_ata, through: :itens_da_ata, source: :item_do_lote
	has_many :documentos_da_ata, class_name: 'Licitacao::DocumentoDaAta', dependent: :destroy
	has_many :aditivos_da_ata, class_name: "Licitacao::AditivoDaAta", dependent: :restrict_with_exception
	has_many :itens_do_aditivo_da_ata, through: :aditivos_da_ata
	has_many :ganhadores, through: :itens_da_ata
	has_many :erratas_da_ata, class_name: 'Licitacao::ErrataDaAta'
	has_many :criticas_de_envio_pncp, as: :modulo, class_name: "Pncp::CriticasDeEnvio"

	accepts_nested_attributes_for :unidades_orcamentarias_da_ata, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :itens_da_ata, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :contratos, reject_if: :all_blank, allow_destroy: true

	validates_associated :unidades_orcamentarias_da_ata
	validates_associated :itens_da_ata

	validates :unidades_orcamentarias_da_ata, uniq_nested_attributes: { atributo: :unidade_orcamentaria_id, mensagem: "unidade orçamentária deve ser única dentro de uma ata" }
	validates :itens_da_ata, uniq_nested_attributes: { atributo: :item_do_lote_id, mensagem: "item deve ser único dentro da ata" }

	delegate  :empenhos_diretos, to: :processo

	after_create :cria_unidade_orcamentaria_por_ata

	validates_presence_of :numero, :data_inicio_de_vigencia, :data_final_de_vigencia
	validates_length_of :numero, :maximum => 30
	validates_uniqueness_of :numero

	enum status: { aberto: 0, confirmado: 1 }

	aasm column: :status, enum: true, whiny_transitions: false do
		state :aberto, :initial => true
		state :confirmado

		event :confirmar do
			transitions from: :aberto, to: :confirmado do
				guard do
					itens_da_ata.any?
				end
			end

			after do
				cria_mensagem_ata_confirmada self
			end
		end

		event :reabrir do
			transitions from: :confirmado, to: :aberto do
				guard do
					contratos.empty?
				end
			end
		end
	end

	def unidades_por_usuario(usuario_utilizado)
		if  self.processo.pedido.verifica_acesso_do_usuario_principal(usuario_utilizado)
			unidades_orcamentarias = self.unidades_orcamentarias_da_ata.includes([unidade_orcamentaria: [:unidade_gestora, :orgao]])
		else
			unidades_por_usuario_ids = usuario_utilizado.unidades_orcamentarias_por_usuario.pluck(:unidade_orcamentaria_id)
			unidades_orcamentarias = self.unidades_orcamentarias_da_ata.includes([unidade_orcamentaria: [:unidade_gestora, :orgao]]).where('unidade_orcamentaria_id in (?)', unidades_por_usuario_ids)
		end

		return unidades_orcamentarias
	end

	def alertar_dias_para_encerrar_ata?
		return false if Configuracao.last.qtd_dias_para_encerrar_a_ata.blank?

		tempo_restante > 0 && tempo_restante <= Configuracao.last.try(:qtd_dias_para_encerrar_a_ata) \
			&& Configuracao.last.try(:qtd_dias_para_encerrar_a_ata) > 0
	end

	def tempo_restante
		((data_final_de_vigencia || Date.today) - Date.today).to_whole
	end

	def por_desconto?
		self.processo.pedido.contem_itens_por_desconto?
	end

	def por_valor_previsto?
		self.processo.pedido.por_valor_previsto?
	end

	def tem_aditivos?
		aditivos_da_ata.any?
	end

	def valor_dos_aditivos_de_reajuste_de_valor
		aditivos_da_ata.confirmados.to_a.sum(&:valor_total).to_f
	end

	# CALLBACKS
	def cria_unidade_orcamentaria_por_ata
		unidades_orcamentarias_da_ata.create(unidade_orcamentaria_id: self.processo.pedido.unidade_orcamentaria.id) if unidades_orcamentarias_da_ata.present?
	end

	def contratos_com_discriminacao_de_itens?
		if contratos.present?
			contratos.first.discriminacao_obrigatoria_de_itens?
		else
			true
		end
	end

	# ASSOCIAÇÕES
	def itens_das_unidades_selecionadas
		unidades_selecionadas_ids = unidades_orcamentarias_da_ata.pluck(:unidade_orcamentaria_id)

		if self.processo.pedido.projeto_simplificado?
			itens_dos_lotes = processo.itens_do_lote.itens_dos_lotes_ativos
				.joins(item_do_pedido: { itens_do_pedido_por_unidade_orcamentaria: :unidade_orcamentaria_por_pedido })
				.where(licitacao_unidades_orcamentarias_por_pedido: { unidade_orcamentaria_id: unidades_selecionadas_ids })
		else
			itens_dos_lotes = processo.itens_do_lote.itens_dos_lotes_ativos
				.joins(:itens_do_projeto_por_pessoa, item_do_pedido: { itens_do_pedido_por_unidade_orcamentaria: :unidade_orcamentaria_por_pedido })
				.where(licitacao_unidades_orcamentarias_por_pedido: { unidade_orcamentaria_id: unidades_selecionadas_ids })
				.where(licitacao_itens_do_projeto_por_pessoa: {final: true, valido: true} )
		end

		if self.processo.homologado_parcialmente?
			id_dos_itens_dos_lotes_ja_cadastrados = Licitacao::ItemDaAta.where(ata_de_registro_de_preco_id: self.processo.atas_de_registro_de_precos.ids).pluck(:item_do_lote_id)
			return itens_dos_lotes.joins(:lote).where.not( licitacao_lotes: {ganhador_id: nil}, licitacao_itens_do_lote: { id: id_dos_itens_dos_lotes_ja_cadastrados }).distinct
		else
			return itens_dos_lotes.distinct
		end
	end

	def valor_a_contratar_por_unidade (unidade_orcamentaria)
		itens_da_ata.inject(0) do |soma, item_da_ata|
			soma + item_da_ata.valor_a_contratar_por_unidade(unidade_orcamentaria.id)
		end
	end

	def valor_a_contratar_por_unidade_gestora(unidade_gestora)
    @unidade_gestora = Loa::UnidadeGestora.find(unidade_gestora)
		@unidade_gestora.unidades_orcamentarias.inject(0) do |soma, unidade_orcamentaria|
      soma + itens_da_ata.inject(0) do |subtotal, item_da_ata|
        subtotal + item_da_ata.valor_a_contratar_por_unidade(unidade_orcamentaria.id)
      end
		end	
	end

	def valor_total_por_unidade (unidade_orcamentaria)
		itens_da_ata.inject(0) do |soma, item_da_ata|
			soma + item_da_ata.valor_a_total_por_unidade(unidade_orcamentaria.id)
		end
	end

	def valor_total_por_unidade_gestora(unidade_gestora)
		@unidade_gestora = Loa::UnidadeGestora.find(unidade_gestora)
		@unidade_gestora.unidades_orcamentarias.inject(0) do |soma, unidade_orcamentaria|
			soma + itens_da_ata.inject(0) do |soma_item, item_da_ata|
				soma_item + item_da_ata.valor_a_total_por_unidade(unidade_orcamentaria.id)
			end
		end
	end
	

	def valor_total_por_lote (lote)
		Licitacao::Lote.find(lote).itens_do_lote.sum(&:preco_final)
	end

	# VALORES
	def valor_total
		return processo.valor_total if unidades_e_itens_vazios?

		itens_da_ata.includes([:ata_de_registro_de_precos, item_do_lote: [lote: :processo, item_do_pedido: :pedido]]).sum(&:valor_total_por_unidade_sem_aditivos) + valor_dos_aditivos_de_reajuste_de_valor.to_f
	end

	def valor_contratado_sem_aditivos
		contratos.includes([:ata_de_registro_de_precos]).sum(&:valor_do_contrato)
	end

	def valor_empenhado_diretamente
		empenhos_diretos.sum(&:definir_valor_do_empenho)
	end

	def valor_total_a_contratar_das_unidades_orcamentarias
		self.unidades_orcamentarias.inject(0) { |total, unidade_orcamentaria|
			total += valor_a_contratar_por_unidade(unidade_orcamentaria).to_d
		}
	end

	def valor_a_contratar
		valor_total - valor_contratado_sem_aditivos - valor_empenhado_diretamente
	end

	# BOOLEANS
	def vencida?
		Date.today > self.data_final_de_vigencia.to_date
	end

	def unidades_e_itens_vazios?
		unidades_orcamentarias_da_ata.empty? && itens_da_ata.empty?
	end
end
