module Licitacao
class OrdensDeCompraController < ApplicationController
	include TradutorConcern
	include LicitacaoHelper
	include ControllerConcern
	include LicitacaoControllersConcern

	skip_before_action :verifica_se_sessao_eh_de_licitacao!
	before_action :authenticate_usuario!
	before_action :autoriza_usuario!, except: [:listar_itens_da_ordem_de_compra, :editar_itens, :atualiza_itens, :recusar]
	before_action :autoriza_com_base_em_create, only: [:editar_itens, :atualiza_itens]
	before_action :set_ordem_de_compra, except: [:index, :new, :create, :cadastro_por_index]
	before_action :disponibiliza_dependencias, only: [:index, :new, :create, :edit, :update]
	before_action :set_empenho, only: [:new, :create, :edit, :update, :disponibiliza_dependencias_itens]
	before_action :verifica_status_do_empenho, only:[:new, :edit]
	before_action :disponibiliza_dependencias_almoxarifados, only: [:new, :edit]
	before_action :disponibiliza_dependencias_cadastro_index, only: [:cadastro_por_index]
	before_action :disponibiliza_exclusivas_do_index, only: [:index]
	before_action -> { verifica_acesso_usuario(@ordem_de_compra) }, except: [:index, :new, :create]

	# GET /licitacao/ordens_de_compra
	def index
		if self.formats.include?(:json)
			@q = Licitacao::OrdemDeCompra.order("id DESC").limit(500).ransack(params[:q])
			@ordens_de_compra = @q.result
		else
			@q =
				if logado_na_gestao_de_estoque? && params[:enviadas_para_almoxarifado].present?
					current_usuario.ordens_de_compra.order("data_da_solicitacao DESC").where(status: Licitacao::OrdemDeCompra.status[:enviado_para_almoxarifado]).search(params[:q])
				elsif logado_na_gestao_de_estoque? && params[:recebidas_parcialmente_pelo_almoxarifado].present?
					current_usuario.ordens_de_compra.order("data_da_solicitacao DESC").where(status: Licitacao::OrdemDeCompra.status[:recebido_parcialmente_pelo_almoxarifado]).search(params[:q])
				elsif logado_na_gestao_de_estoque? && params[:recebidas_pelo_almoxarifado].present?
					current_usuario.ordens_de_compra.order("data_da_solicitacao DESC").where(status: Licitacao::OrdemDeCompra.status[:recebido_pelo_almoxarifado]).search(params[:q])
				elsif logado_na_gestao_de_estoque? && params[:recusadas_pelo_almoxarifado].present?
					current_usuario.ordens_de_compra.order("data_da_solicitacao DESC").where(status: Licitacao::OrdemDeCompra.status[:recusado_pelo_almoxarifado]).search(params[:q])
				elsif logado_na_gestao_de_estoque?
					current_usuario.ordens_de_compra.order("data_da_solicitacao DESC").where.not(
						status: [
							Licitacao::OrdemDeCompra.status[:aberto],
							Licitacao::OrdemDeCompra.status[:fechado],
							Licitacao::OrdemDeCompra.status[:cancelado]
						]
					).search(params[:q])
				else
					current_usuario.ordens_de_compra.order(data_da_solicitacao: :desc, numero: :desc).search(params[:q])
				end

			if logado_no_administrativo?
				@ordens_de_compra = @q.result(distinct: false).where(orcamento: contexto_atual).paginate(page: params[:page], per_page: 10)
			else	
				@ordens_de_compra = @q.result(distinct: false).where(orcamento: contexto_atual).joins(almoxarifado: :unidades_orcamentarias_do_almoxarifado)
					.where("gestao_de_estoque_unidades_orcamentarias_do_almoxarifado.unidade_orcamentaria_id in (?)", current_usuario.unidades_orcamentarias_por_usuario.pluck(:unidade_orcamentaria_id))
					.distinct.paginate(page: params[:page], per_page: 10)
		end
	end

		@pessoas = Base::Pessoa.includes(:tipo_de_pessoa).order(:nome)
		@unidades_gestoras = current_usuario.unidades_gestoras.do_exercicio(exercicio_atual).order("loa_unidades_gestoras.codigo::integer").uniq
	end

	# GET /licitacao/ordens_de_compra/1
	def show
		respond_to do |format|
			format.html
			format.json
		end
	end

	# GET /licitacao/ordens_de_compra/new
	def new
		ordem_do_empenho = @empenho.ordens_de_compra.find_by(id: params[:ordem_de_compra_id]) if params[:ordem_de_compra_id].present?
		if (@empenho.saldo_para_ordem_de_compra > 0 && !params[:ordem_de_compra_id].present? ) || ( params[:ordem_de_compra_id].present? && ordem_do_empenho.try(:quantidade_a_receber).to_f > 0 )
			@ordem_de_compra = @empenho.ordens_de_compra.new
			@ordem_de_compra.ordem_de_compra_id = params[:ordem_de_compra_id]
		else
			if params[:ordem_de_compra_id].present? && ordem_do_empenho.try(:quantidade_a_receber).to_f <= 0
				redirect_to empenho_path(@empenho), alert: 'Não existe quantidade disponivel nessa ordem de compra.'
			else
				redirect_to empenho_path(@empenho), alert: 'Empenho não possui saldo para novas ordens de compra.'
			end
		end
	end

	# POST /licitacao/ordens_de_compra
	def create
		@ordem_de_compra = contexto_atual.ordens_de_compra.new(ordem_de_compra_params)
		if @ordem_de_compra.save
			if @ordem_de_compra.empenho.itens_do_empenho.any?
				redirect_to editar_itens_ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento foi criada com sucesso.'
			else
				redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento foi criada com sucesso.'
			end
		else
			if ordem_de_compra_params[:exercicio].present?
				disponibiliza_dependencias_cadastro_index
				mensagem = 'Empenho não tem itens' if @ordem_de_compra.errors[:base].include?("Empenho selecionado não tem itens")
				flash.now[:alert] = "Não foi possível criar a ordem de fornecimento. Verifique os campos. #{mensagem}"
				render :new
			else
				@empenho = @ordem_de_compra.empenho
				disponibiliza_dependencias_almoxarifados
				flash.now[:alert] = 'Não foi possível criar a ordem de fornecimento. Verifique os campos.'
				render :new
			end
		end
	end

	# GET /licitacao/ordens_de_compra/1/edit
	def edit
	end

	# PATCH/PUT /licitacao/ordens_de_compra/1
	def update
		begin
			if @ordem_de_compra.update(ordem_de_compra_params)
				redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento foi atualizada com sucesso.'
			else
				disponibiliza_dependencias_almoxarifados
				flash.now[:alert] = 'Não foi possível atualizar a ordem de fornecimento. Verifique os campos.'
				render :edit
			end
		rescue => e
			disponibiliza_dependencias_almoxarifados
			flash[:alert] = e.message
			render :edit
		end
	end

	# DELETE /licitacao/ordens_de_compra/1
	def destroy
		mensagem = apaga_e_retorna_mensagem(@ordem_de_compra)
		redirect_to empenho_path(@ordem_de_compra.empenho), mensagem
	end

	# PATCH /licitacao/ordens_de_compra/fechar/1
	def fechar
		begin
			if @ordem_de_compra.fechar!
				redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento foi fechada com sucesso.'
			else
				flash.now[:alert] = @ordem_de_compra.errors.full_messages.to_sentence
				render :show
			end
		rescue Exception => e
			flash[:alert] = e.message
			render :show
		end
	end

	# PATCH /licitacao/ordens_de_compra/1/retornar_para_aberto
	def retornar_para_aberto
		begin
			if @ordem_de_compra.retornar_para_aberto!
				redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento foi aberta com sucesso.'
			else
				flash.now[:alert] = @ordem_de_compra.errors.full_messages.to_sentence
				render :show
			end
		rescue Exception => e
			flash[:alert] = e.message
			render :show
		end
	end

	# PATCH /licitacao/ordens_de_compra/1/liberar_saldo_dos_itens
	def liberar_saldo_dos_itens
		begin
			if @ordem_de_compra.liberar_saldo_dos_itens!
				redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Saldo restante dos itens liberado com sucesso.'
			else
				flash.now[:alert] = @ordem_de_compra.errors.full_messages.to_sentence
				render :show
			end
		rescue Exception => e
			flash[:alert] = e.message
			render :show
		end
	end

	# PATCH /licitacao/ordens_de_compra/1/enviar_para_almoxarifado
	def enviar_para_almoxarifado
		if @ordem_de_compra.enviar_para_almoxarifado!
			redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento enviada com sucesso para o almoxarifado.'
		else
			render :show
		end
	end

	def retornar_para_administrativo
		if @ordem_de_compra.devolvido_pelo_almoxarifado!
			redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento foi devolvida para o administrativo.'
		end
	end

	# GET /licitacao/pedidos/1/cancelar
	def confirmar_cancelamento
		return if bloqueia_usuario_com_base_em 'cancelar'
	end

	def cancelar
		@ordem_de_compra.motivo_do_cancelamento = cancelamento_params[:motivo_do_cancelamento]
		if @ordem_de_compra.cancelar!
			redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento foi cancelada com sucesso.'
		else
			render :confirmar_cancelamento
		end
	end

	def recusar
		return if bloqueia_usuario_com_base_em 'update'
		@ordem_de_compra.motivo_da_recusa = recusa_params[:motivo_da_recusa]
		if @ordem_de_compra.recusar!
			redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento foi recusada com sucesso.'
		else
			render :recusar_recebimento
		end
	end

	def editar_itens
		disponibiliza_dependencias_itens
		@ordem_de_compra.itens_da_ordem_de_compra.build if @ordem_de_compra.itens_da_ordem_de_compra.empty?
		if @ordem_de_compra.ordem_de_compra_primaria.present?
			@ordem_de_compra.save!
			@ordem_de_compra.ordem_de_compra_primaria.liberar_saldo_dos_itens!
			redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Ordem de fornecimento foi atualizada com sucesso.'
		end
	end

	def atualiza_itens
		if @ordem_de_compra.update(ordem_de_compra_params)
			redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'Itens atualizados com sucesso.'
		else
			disponibiliza_dependencias_itens_variaveis
			flash[:alert] = "Erro ao atualizar os itens. Verifique os campos."
			render :editar_itens
		end
	end

	def enviar_ordem_de_compra_por_email
		begin
			enviar_email_ordem_de_compra(@ordem_de_compra.id)
			redirect_to ordem_de_compra_path(@ordem_de_compra), notice: 'E-mail enviado com sucesso!'
		rescue Net::SMTPAuthenticationError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Net::SMTPFatalError, Net::SMTPUnknownError => e
			redirect_to ordem_de_compra_path(@ordem_de_compra), notice: "Erro ao enviar o e-mail. #{e}"
		end
	end

	def listar_itens_da_ordem_de_compra
		@ordem_de_compra = Licitacao::OrdemDeCompra.find(params[:id])
		@itens = @ordem_de_compra.itens_da_ordem_de_compra
		@unidades_de_medida = UnidadeDeMedida.all

		respond_to do |format|
			format.js
		end
	end

	def cadastro_por_index
		@ordem_de_compra = Licitacao::OrdemDeCompra.new
		@ordem_de_compra.exercicio = contexto_atual.id unless @ordem_de_compra.exercicio.present?
		render :new
	end

	def disponibiliza_exclusivas_do_index
		@almoxarifados = GestaoDeEstoque::Almoxarifado.joins(:unidades_orcamentarias_do_almoxarifado)
			.where("gestao_de_estoque_almoxarifados.orcamento_id = ? and gestao_de_estoque_unidades_orcamentarias_do_almoxarifado.unidade_orcamentaria_id in (?)", contexto_atual.id, current_usuario.unidades_orcamentarias_por_usuario.pluck(:unidade_orcamentaria_id))
			.where("tipo_de_almoxarifado <> 9").order(:id).joins(unidades_orcamentarias: [:orcamento]).where(orcamentos: {id: contexto_atual.id}).uniq
		@tipos_de_ordem = Licitacao::OrdemDeCompra.tipos_de_ordem_de_compra
	end

	private
	def set_ordem_de_compra
		ordem_de_compra_id = params[:id] || params[:ordem_de_compra_id]
		@ordem_de_compra = OrdemDeCompra.find( ordem_de_compra_id )
	end

	def set_empenho
		if params[:empenho_id].present?
			@empenho = Contabilidade::Empenho.find(params[:empenho_id])
		elsif @ordem_de_compra.present?
			@empenho = @ordem_de_compra.empenho
		end
	end

	def disponibiliza_dependencias
		if params[:contrato_id].present?
			@contrato = Licitacao::Contrato.find(params[:contrato_id])
			@processos = [@contrato.projeto]
		else
			@processos = current_usuario.projetos.homologado.order(numero_do_processo: :desc)
		end
		@contratos = current_usuario.contratos.do_exercicio(exercicio_atual)
		@status = Licitacao::OrdemDeCompra.status
	end

	def disponibiliza_dependencias_almoxarifados
		empenho = @ordem_de_compra.try(:empenho).try(:present?) ? @ordem_de_compra.empenho : @empenho
		@unidades_orcamentarias_do_almoxarifado = GestaoDeEstoque::UnidadeOrcamentariaDoAlmoxarifado.where(unidade_orcamentaria_id: empenho.unidade_orcamentaria.id)
		@almoxarifados = GestaoDeEstoque::Almoxarifado.where("orcamento_id = ? AND tipo_de_almoxarifado != 9", contexto_atual.id).joins(:unidades_orcamentarias_do_almoxarifado).where("gestao_de_estoque_unidades_orcamentarias_do_almoxarifado.unidade_orcamentaria_id = ?", empenho.unidade_orcamentaria.id) || Array.new
		@pessoas = Base::Pessoa.order(:nome) || Array.new
	end

	def disponibiliza_dependencias_itens
		@itens_adicionados = @ordem_de_compra.itens_da_ordem_de_compra.map{ |item|
			[item.id, item.item_id, item.marca, item.valor_unitario, item.total, item.quantidade ]
		}
		@itens_adicionados_id = @itens_adicionados.map { |e| e[1] }
		@ordem_de_compra.itens_da_ordem_de_compra.delete_all
		@ordem_de_compra.reload
		if @ordem_de_compra.empenho.itens_do_empenho.present? && @ordem_de_compra.descrimina_itens_do_empenho.present?
			if @itens_adicionados.present?
				@itens_adicionados.each do |item_da_ordem|
					@ordem_de_compra.itens_da_ordem_de_compra.find_or_initialize_by(id: item_da_ordem[0], item_id: item_da_ordem[1], marca: item_da_ordem[2], valor_unitario: item_da_ordem[3], total: item_da_ordem[4], quantidade: item_da_ordem[5])
				end
			end
			@ordem_de_compra.empenho.itens_do_empenho.distinct.each do |item_do_empenho|
				if item_do_empenho.saldo_disponivel_para_ordem_de_compra.to_f > 0
					item_da_ordem_de_compra = @ordem_de_compra.itens_da_ordem_de_compra.find_by(item_id: item_do_empenho.item.id)
					@ordem_de_compra.itens_da_ordem_de_compra.find_or_initialize_by(item: item_do_empenho.item) unless item_da_ordem_de_compra.present? || @itens_adicionados_id.include?(item_do_empenho.item_id)
				end
			end
		elsif @ordem_de_compra.empenho.itens_do_empenho.blank? || @ordem_de_compra.descrimina_itens_do_empenho.blank?
			if @itens_adicionados.present?
				@itens_adicionados.each do |item_da_ordem|
					@ordem_de_compra.itens_da_ordem_de_compra.find_or_initialize_by(id: item_da_ordem[0], item_id: item_da_ordem[1], marca: item_da_ordem[2], valor_unitario: item_da_ordem[3], total: item_da_ordem[4], quantidade: item_da_ordem[5])
				end
			end
			if @ordem_de_compra.ordem_de_compra_primaria.present?
				if @ordem_de_compra.ordem_de_compra_primaria.possui_saldo_para_requisitar?
					@ordem_de_compra.ordem_de_compra_primaria.itens_da_ordem_de_compra.each do |item_da_ordem_primaria|
						total = (item_da_ordem_primaria.valor_unitario.to_f * item_da_ordem_primaria.quantidade_a_receber.to_f)
						@ordem_de_compra.itens_da_ordem_de_compra.find_or_initialize_by(item_id: item_da_ordem_primaria.item_id, marca: item_da_ordem_primaria.marca, valor_unitario: item_da_ordem_primaria.valor_unitario, total: total, quantidade: item_da_ordem_primaria.quantidade_a_receber) unless item_da_ordem_primaria.quantidade_a_receber.to_f == 0 || @itens_adicionados_id.include?(item_da_ordem_primaria.item_id)
					end
				end
			else
				@itens =  Base::Item.where(esconder: false).includes(:unidade_de_medida).map { |item|
					[
						item.codigo_descricao_unidade_codigo_da_prefeitura,
						item.id,
					]
				}
				@itens_select = @itens
			end
		end
	end

	def disponibiliza_dependencias_itens_variaveis
		if @ordem_de_compra.empenho.itens_do_empenho.blank? || @ordem_de_compra.descrimina_itens_do_empenho.blank?
			if @ordem_de_compra.ordem_de_compra_primaria.present?
				@itens_da_ordem = @ordem_de_compra.ordem_de_compra_primaria.itens_da_ordem_de_compra.map(&:item_id)
				@itens =  Base::Item.where("id in (?)", @itens_da_ordem).includes(:unidade_de_medida).map { |item|
					[
						item.codigo_descricao_unidade_codigo_da_prefeitura,
						item.id,
					]
				}
				@itens_select = @itens
			else
				@itens =  Base::Item.where(esconder: false).includes(:unidade_de_medida).map { |item|
					[
						item.codigo_descricao_unidade_codigo_da_prefeitura,
						item.id,
					]
				}
				@itens_select = @itens
			end
		end
	end

	def verifica_status_do_empenho
		if @ordem_de_compra.present? && @ordem_de_compra.empenho.present?
			@empenho = @ordem_de_compra.empenho
		else
			@empenho = Contabilidade::Empenho.find( params[:empenho_id] )
		end

		unless @empenho.confirmado?
			redirect_back fallback_location: empenho_path(@empenho), alert: 'Não é possível adicionar ordem de compra a um empenho não confirmado.'
		end
	end

	def autoriza_com_base_em_create
		return if bloqueia_usuario_com_base_em 'create'
	end

	def disponibiliza_dependencias_cadastro_index
		@orcamentos = Orcamento.all.order(exercicio: :desc)
		@unidades_orcamentarias = Loa::UnidadeOrcamentaria.joins(:orgao).where("loa_orgaos.orcamento_id = ?", @ordem_de_compra.try(:exercicio)) || Array.new
		@empenhos = Contabilidade::Empenho.where("contabilidade_empenhos.id = ?", @ordem_de_compra.try(:empenho_id)) || Array.new
		@almoxarifados = GestaoDeEstoque::Almoxarifado.where("gestao_de_estoque_almoxarifados.orcamento_id = ? and gestao_de_estoque_almoxarifados.id = ?", contexto_atual.id, @ordem_de_compra.try(:almoxarifado_id)) || Array.new
		@pessoas = Base::Pessoa.order(:nome) || Array.new
	end

	# Permite apenas os parâmetros específicos
	def ordem_de_compra_params
		params.require(:licitacao_ordem_de_compra).permit(:prazo_de_entrega, :descrimina_itens_do_empenho,
			:setor_solicitante,:observacao, :local_de_entrega, :endereco, :ordem_de_compra_id,
			:data_da_solicitacao, :status, :motivo_do_cancelamento, :motivo_da_recusa, :empenho_id, :almoxarifado_id, :exercicio, 
			:unidade_orcamentaria_form, :avulso, :dados_do_faturamento_pessoa_id,
			itens_da_ordem_de_compra_attributes: [
				:id, :item_id, :ordem_de_compra_id, :quantidade, :valor_unitario, :total, :marca, :item_quantidade, :_destroy
			]
		)
	end

	def cancelamento_params
		params.require(:licitacao_ordem_de_compra).permit(:motivo_do_cancelamento).merge(status: 'cancelado')
	end

	def recusa_params
		params.require(:licitacao_ordem_de_compra).permit(:motivo_da_recusa).merge(status: 'recusado_pelo_almoxarifado')
	end
end
end
