module Administrativo
	class RequisicoesDeMateriaisController < ApplicationController
		include ControllerConcern

		before_action :authenticate_usuario!
		before_action :autoriza_usuario!, except: [
			:reabrir_requisicao, :fechar_requisicao, :enviar_requisicao_ao_almoxarifado, :atualiza_itens_das_requisicoes_de_materiais,
			:receber_no_almoxarifado, :atender_requisicao, :recusar_requisicao, :recusar, :editar_itens_das_requisicoes_de_materiais,
			:concluir_atendimento_parcial, :concluir_atendimento, :adicionar_todos_os_itens_das_requisicoes_de_materiais,
			:devolucao_de_material, :atualiza_devolucao_de_material, :demanda_programada, :atualiza_demanda_programada, :confirmar_multiplas_requisicoes, :concluir_consumo
		]
		before_action :set_requisicao_de_material, only: [
			:show, :edit, :update, :destroy, :recusar, :itens_das_requisicoes_de_materiais, :atualiza_itens_das_requisicoes_de_materiais,
			:reabrir_requisicao, :fechar_requisicao, :enviar_requisicao_ao_almoxarifado, :editar_itens_das_requisicoes_de_materiais,
			:receber_no_almoxarifado, :atender_requisicao, :recusar_requisicao, :recusar,
			:concluir_atendimento_parcial, :concluir_atendimento, :atualiza_devolucao_de_material, :devolucao_de_material,
			:demanda_programada, :atualiza_demanda_programada, :concluir_consumo, :retornar_ao_administrativo
		]
		before_action :disponibiliza_dependencias_itens, only: [:editar_itens_das_requisicoes_de_materiais, :atualiza_itens_das_requisicoes_de_materiais]
		before_action :disponibiliza_dependencias, only: [:index, :new, :create, :edit, :update, :devolucao_de_material, :atualiza_devolucao_de_material]
		# before_action -> {verifica_mes_bloqueado(@requisicao_de_material)}, only: [:edit, :destroy]

		# GET /administrativo/requisicoes_de_materiais
		def index
			@almoxarifados = GestaoDeEstoque::Almoxarifado.order('id ASC')
			@q =
				if @tipo.present?
					if @tipo.eql?('solicitacao_consumo')
						contexto_atual.requisicoes_de_materiais.where(tipo_de_solicitacao: @tipo).order("data_da_requisicao DESC").search(params[:q])
					else
						contexto_atual.requisicoes_de_materiais.where.not(classificacao: nil).order("data_da_requisicao DESC").search(params[:q])
					end
				else
					status_da_requisicao = Administrativo::RequisicaoDeMaterial.status
					status = status_da_requisicao.values_at('fechado', 'cancelado')
					status.push(status_da_requisicao['aberto']) unless logado_no_administrativo?

					contexto_atual.requisicoes_de_materiais.where(avulsa: !configuracao.usa_modulo_administrativo?, classificacao: nil).where.not(status: status).order("data_da_requisicao DESC").search(params[:q])
				end

			@requisicoes_de_materiais = @q.result(distinct: false).paginate(page: params[:page], per_page: 10)
		end

		# GET /administrativo/requisicoes_de_materiais/1
		def show
		end

		# GET /administrativo/requisicoes_de_materiais/new
		def new
			@requisicao_de_material = Administrativo::RequisicaoDeMaterial.new
			@requisicao_de_material.preenche_campos_requisicao_de_material params[:ordem_de_compra_id]
			@unidades_orcamentarias_origem  = contexto_atual.unidades_orcamentarias_com_itens_no_almoxarifado(current_usuario)
			@requisicao_de_material.tipo_de_solicitacao = @tipo.eql?('solicitacao_consumo') ? @tipo : 'solicitacao_requisicao'
			ordem_de_compra_id = params[:ordem_de_compra_id]

			if @tipo.present?
				if @requisicao_de_material.classificacao.nil? && @requisicao_de_material.solicitacao_requisicao?
					@requisicao_de_material.classificacao = @requisicao_de_material.class.classificacoes[:doacao]
				end
				@requisicao_de_material.detalhamentos_da_requisicao_de_material.build()
			elsif ordem_de_compra_id.present?
				@requisicao_de_material.avulsa = false
			end

		end

		# GET /administrativo/requisicoes_de_materiais/1/edit
		def edit
			@unidades_orcamentarias_origem  = contexto_atual.unidades_orcamentarias_com_itens_no_almoxarifado(current_usuario)
		end

		# POST /administrativo/requisicoes_de_materiais
		def create
			@requisicao_de_material = Administrativo::RequisicaoDeMaterial.new(requisicao_de_material_params)
			@requisicao_de_material.orcamento = contexto_atual
			@requisicao_de_material.usuario_id = current_usuario.try(:id)

			if @requisicao_de_material.trazer_itens_do_recebimento
				@requisicao_de_material.detalhamentos_da_requisicao_de_material.destroy_all
			end

			@requisicao_de_material.transaction do
				if @requisicao_de_material.save
					redirect_to administrativo_editar_itens_das_requisicoes_de_materiais_path(@requisicao_de_material)
				else
					disponibiliza_dependencias
					@unidades_orcamentarias_origem  = contexto_atual.unidades_orcamentarias_com_itens_no_almoxarifado(current_usuario)
					render :new
				end
			rescue Exception => e
				raise e
				raise ActiveRecord::Rollback
			end
		end

		# PATCH/PUT /administrativo/requisicoes_de_materiais/1
		def update
			@requisicao_de_material.transaction do

				if @requisicao_de_material.update( requisicao_de_material_params )
					redirect_to @requisicao_de_material, notice: 'Requisicao de material foi atualizado(a) com sucesso.'
				else
					render :edit
				end
			rescue Exception => e
				raise e
				raise ActiveRecord::Rollback
			end
		end

		# DELETE /administrativo/requisicoes_de_materiais/1
		def destroy
			mensagem = apaga_e_retorna_mensagem(@requisicao_de_material)
			redirect_to administrativo_requisicoes_de_materiais_url, mensagem
		end

		def reabrir_requisicao
			return if bloqueia_usuario_com_base_em 'update'
			if @requisicao_de_material.reabrir_requisicao!
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: 'A requisição foi reaberta com sucesso.'
			else
				render :show
			end
		end

		def fechar_requisicao
			return if bloqueia_usuario_com_base_em 'update'
			if @requisicao_de_material.fechar_requisicao!
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: 'A requisição foi fechada com sucesso.'
			else
				render :show
			end
		end

		def enviar_requisicao_ao_almoxarifado
			return if bloqueia_usuario_com_base_em 'update'
			if @requisicao_de_material.enviar_ao_almoxarifado!
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: 'A requisição foi enviada ao almoxarfiado com sucesso.'
			else
				render :show
			end
		end

		def receber_no_almoxarifado
			return if bloqueia_usuario_com_base_em 'update'
			if @requisicao_de_material.receber_no_almoxarifado!
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: 'A requisição foi recebida no almoxarfiado com sucesso.'
			else
				render :show
			end
		end

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

		def atender_requisicao
			return if bloqueia_usuario_com_base_em 'update'
			if @requisicao_de_material.atender_requisicao!
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: 'Atendimento iniciado com sucesso.'
			else
				render :show
			end
		end

		def concluir_atendimento_parcial
			return if bloqueia_usuario_com_base_em 'update'
			if @requisicao_de_material.concluir_atendimento_parcial!
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: 'Atendimento parcial concluído com sucesso.'
			else
				render :show
			end
		end

		def concluir_atendimento
			return if bloqueia_usuario_com_base_em 'update'
			if @requisicao_de_material.concluir_atendimento!
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: 'Atendimento concluído com sucesso.'
			else
				render :show
			end
		end

		def adicionar_todos_os_itens_das_requisicoes_de_materiais
			if params[:todos].present? && params[:todos] == "true"
				if @requisicao_de_material.trazer_itens_do_recebimento?
					itens_da_requisicao_ids = @requisicao_de_material.recebimento_de_material.itens_do_recebimento_de_materiais.pluck(:item_id)
					@requisicao_de_material.recebimento_de_material.itens_do_recebimento_de_materiais.each do |item_da_requisicao|
						estoque_id = GestaoDeEstoque::Estoque.find_by(almoxarifado_id: @requisicao_de_material.almoxarifado_id ,unidade_orcamentaria_id: @requisicao_de_material.unidade_orcamentaria_id, item_id: item_da_requisicao.item_id)
						@requisicao_de_material.itens_das_requisicoes_de_materiais.build(
							item_id: item_da_requisicao.item_id,
							unidade_de_medida_id: estoque_id.unidade_de_medida_id,
							estoque_id: estoque_id.id
						)
					end
				end
			end
		end

		def atualiza_itens_das_requisicoes_de_materiais
			return if bloqueia_usuario_com_base_em 'update'
			@requisicao_de_material.transaction do
				if @requisicao_de_material.update(itens_das_requisicoes_de_materiais_params)
					mensagem = 'Itens atualizados com sucesso.'
					if params[:atender_todos].present?
						@requisicao_de_material.atender_todos_os_itens
						mensagem = 'Todos os itens foram atendidos com sucesso'
					end
					redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: mensagem
				else
					render :editar_itens_das_requisicoes_de_materiais
				end
			rescue Exception => e
				disponibiliza_dependencias
				sub_elementos_do_detalhamento = @requisicao_de_material.detalhamentos_da_requisicao_de_material.map { |drm| drm.sub_elemento_de_despesa.id }
				@itens_da_requisicao = GestaoDeEstoque::Estoque.where(almoxarifado_id: @requisicao_de_material.almoxarifado_id ,unidade_orcamentaria_id: @requisicao_de_material.unidade_orcamentaria_id, sub_elemento_de_despesa_id: sub_elementos_do_detalhamento)
				render :editar_itens_das_requisicoes_de_materiais
				raise ActiveRecord::Rollback
			end
		end

		def editar_itens_das_requisicoes_de_materiais
			adicionar_todos_os_itens_das_requisicoes_de_materiais
			@requisicao_de_material.itens_das_requisicoes_de_materiais.build unless @requisicao_de_material.itens_das_requisicoes_de_materiais.present?
			if @requisicao_de_material.detalhamentos_da_requisicao_de_material.present?
				sub_elementos_do_detalhamento = @requisicao_de_material.detalhamentos_da_requisicao_de_material.pluck(:sub_elemento_de_despesa_id)
			else
				sub_elementos_do_detalhamento = @requisicao_de_material.recebimento_de_material.sub_elemento_de_despesa_id
			end
			if sub_elementos_do_detalhamento.present?
				@itens_da_requisicao = GestaoDeEstoque::Estoque.where(
					almoxarifado_id: @requisicao_de_material.almoxarifado_id,
					unidade_orcamentaria_id: @requisicao_de_material.unidade_orcamentaria_id,
					sub_elemento_de_despesa_id: sub_elementos_do_detalhamento
				)
			else
				@itens_da_requisicao = GestaoDeEstoque::Estoque.where(
					almoxarifado_id: @requisicao_de_material.almoxarifado_id,
					unidade_orcamentaria_id: @requisicao_de_material.unidade_orcamentaria_id
				)
			end
		end

		def recusar_requisicao
		end

		def demanda_programada
			return if bloqueia_usuario_com_base_em 'update'
		end

		def atualiza_demanda_programada
			if @requisicao_de_material.update(itens_das_requisicoes_de_materiais_params)
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: 'Demanda programada com sucesso.'
			else
				render :demanda_programada
			end
		end

		#POST /administrativo/requisicoes_de_materiais/confirmar_multiplas_requisicoes
		def confirmar_multiplas_requisicoes
			return if bloqueia_usuario_com_base_em 'update'

			requisicoes_de_materiais = params[:administrativo_requisicao_de_material]
			if requisicoes_de_materiais.nil?
				redirect_to intermodulos_saidas_path, alert: "Nenhuma Saída foi selecionada"
				return
			end
			recebidas = Array.new
			erros = Set.new
			quantidade_enviada = 0
			status_final = ""
			ActiveRecord::Base.transaction do
				requisicoes_de_materiais.each do |id, valor|
					if valor.eql?("1")
						quantidade_enviada += 1
						requisicao_de_material = Administrativo::RequisicaoDeMaterial.find(id.to_s.to_i)
						requisicao_de_material.status = Administrativo::RequisicaoDeMaterial.status[:confirmado]
						if requisicao_de_material.save
							recebidas << id
						else
							requisicao_de_material.errors.full_messages.each do |erro|
								erros << erro
							end
							raise ActiveRecord::Rollback
						end
					end
				end
			end
			if recebidas.size == 0
				if erros.size == 0
					redirect_to intermodulos_saidas_path, alert: "Nenhuma Saída foi confirmada"
				else
					redirect_to intermodulos_saidas_path, alert: "Falha ao confirmar Saídas: #{erros.to_a.join(', ')}"
				end
			elsif recebidas.size == 1
				redirect_to administrativo_requisicao_de_material_path(id: recebidas[0]), success: "Saída confirmada com sucesso"
			else
				redirect_to intermodulos_saidas_path, success: "Todas #{recebidas.size} Saídas foram confirmadas com sucesso"
			end
		end

		def concluir_consumo
			return if bloqueia_usuario_com_base_em 'update'
			if @requisicao_de_material.concluir_consumo!
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), notice: 'Os Itens Foram Consumidos com Sucesso.'
			else
				render :show
			end
		end

		def retornar_ao_administrativo
			return if bloqueia_usuario_com_base_em 'update'
			if @requisicao_de_material.retornar_ao_administrativo!
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), success: 'Retornado ao administrativo com sucesso.'
			else
				redirect_to administrativo_requisicao_de_material_path(@requisicao_de_material), alert: 'Não foi possivel retornar ao administrativo'
			end
		end

		private
		def disponibiliza_dependencias_itens
			@unidades_de_medida = UnidadeDeMedida.order("id ASC")
			@itens_do_recebimento = []

			if @requisicao_de_material.trazer_itens_do_recebimento? && @requisicao_de_material.classificacao.nil? && !@requisicao_de_material.avulsa?
				@itens_do_recebimento = @requisicao_de_material.recebimento_de_material.itens_do_recebimento_de_materiais.includes(:item)
			elsif @requisicao_de_material.classificacao.present? && !@requisicao_de_material.avulsa?
				@itens_do_recebimento = GestaoDeEstoque::ItemDoRecebimentoDeMaterial.joins(:recebimento_de_material).where('gestao_de_estoque_recebimento_de_materiais.avulso = false AND gestao_de_estoque_recebimento_de_materiais.classificacao IS NOT NULL').includes(:item)
			elsif !@requisicao_de_material.trazer_itens_do_recebimento? && @requisicao_de_material.classificacao.nil? && !@requisicao_de_material.avulsa?
				@itens_do_recebimento = GestaoDeEstoque::ItemDoRecebimentoDeMaterial.joins(:recebimento_de_material).where('gestao_de_estoque_recebimento_de_materiais.avulso = false AND gestao_de_estoque_recebimento_de_materiais.classificacao IS NULL').includes(:item)
			else
				@itens_do_recebimento = GestaoDeEstoque::ItemDoRecebimentoDeMaterial.joins(:recebimento_de_material).where('gestao_de_estoque_recebimento_de_materiais.avulso = true AND gestao_de_estoque_recebimento_de_materiais.classificacao IS NULL').includes(:item)
			end

			@itens = @itens_do_recebimento.select { |i| i.possui_saldo_disponivel? }.map do |item_do_recebimento_de_material|
				[
					item_do_recebimento_de_material.item_id,
					item_do_recebimento_de_material.codigo_e_descricao_com_unidade_de_medida_especifica,
					{
						"data-item_do_recebimento_de_material_id" => item_do_recebimento_de_material.id
					}
				]
			end
		end

		def disponibiliza_dependencias
			@unidades_de_medida = UnidadeDeMedida.order("id ASC")
			@tipos_de_requisicoes = Administrativo::RequisicaoDeMaterial.tipos_de_requisicoes
			@tipos_de_materiais = Administrativo::RequisicaoDeMaterial.tipos_de_materiais
			@classificacoes = Administrativo::RequisicaoDeMaterial.classificacoes_i18n
			@unidades_orcamentarias = contexto_atual.unidades_orcamentarias_do_usuario(current_usuario)
			@classificacoes_tipo_de_material = Administrativo::RequisicaoDeMaterial.classificacoes_tipo_de_material
			@almoxarifados = GestaoDeEstoque::Almoxarifado.joins(:unidades_orcamentarias_do_almoxarifado).where("gestao_de_estoque_unidades_orcamentarias_do_almoxarifado.unidade_orcamentaria_id = ?", @requisicao_de_material.try(:unidade_orcamentaria_id)).order("id ASC") || Array.new
			@almoxarifados_destino = GestaoDeEstoque::Almoxarifado.joins(:unidades_orcamentarias_do_almoxarifado).where("gestao_de_estoque_unidades_orcamentarias_do_almoxarifado.unidade_orcamentaria_id = ?", @requisicao_de_material.try(:unidade_orcamentaria_id)).order("id ASC") || Array.new
			@agentes = Base::AgentePublicoMunicipal.all
			@tipo = params[:tipo]
			@classificacoes_do_detalhamento = Administrativo::RequisicaoDeMaterial.classificacoes_tipo_de_material_i18n
			if @requisicao_de_material.present? && @requisicao_de_material.persisted?
				if @requisicao_de_material.recebimento_de_material.present?
					@recebimento_de_materiais = [@requisicao_de_material.recebimento_de_material]
				else
					@recebimento_de_materiais = []
				end
			else
				@recebimento_de_materiais = [] # Ajax
			end
		end

		def set_requisicao_de_material
			@requisicao_de_material = Administrativo::RequisicaoDeMaterial.find(params[:id])
		end

		# Permite apenas os parâmetros específicos
		def requisicao_de_material_params
			params.require(:administrativo_requisicao_de_material)
				.permit(
					:numero_da_requisicao,
					:data_da_requisicao,
					:tipo_de_material,
					:unidade_orcamentaria_id,
					:almoxarifado_id,
					:trazer_itens_do_recebimento,
					:recebimento_de_material_id,
					:motivo_da_recusa,
					:historico,
					:orcamento_id,
					:avulsa,
					:classificacao,
					:almoxarifado_de_destino_id,
					:transferir_todos_os_itens,
					:fornecedor_id,
					:beneficiado_id,
					:usuario,
					:data_da_devolucao,
					:historico_da_devolucao,
					:tipo_de_requisicao,
					:classificacao_tipo_de_material,
					:almoxarifado_destino_id,
					:logado_no_adm,
					:responsavel_id,
					:tipo_de_consumo,
					:tipo_de_solicitacao,
					:sub_elemento_de_despesa_id,
					:utiliza_centro_de_custo,
					itens_das_requisicoes_de_materiais_attributes: [
						:id,
						:item_id,
						:requisicao_de_material_id,
						:unidade_de_medida_id,
						:quantidade_disponivel_attribute,
						:quantidade_requisitada,
						:quantidade_atendida,
						:estoque_id,
						:centro_de_custo_da_requisicao_id,
						:detalhamento_da_requisicao_de_material_id,
						:_destroy,
						demandas_programadas_attributes: [
							:id,
							:item_da_requisicao_de_material_id,
							:quantidade_requisitada,
							:quantidade_atendida,
							:data_do_atendimento,
							:_destroy
						]
					],
					detalhamentos_da_requisicao_de_material_attributes: [
						:id,
						:tipo_de_material,
						:sub_elemento_de_despesa_id,
						:classificacao_do_detalhamento_id,
						:_destroy
					],
					centros_de_custo_da_requisicao_attributes: [
						:id,
						:centro_de_custo_id,
						:marcado_para_cadastro,
						:_destroy
					]
				)
		end

		def itens_das_requisicoes_de_materiais_params
			params.require(:administrativo_requisicao_de_material)
				.permit(
					itens_das_requisicoes_de_materiais_attributes: [
						:id,
						:item_id,
						:requisicao_de_material_id,
						:unidade_de_medida_id,
						:quantidade_disponivel_attribute,
						:quantidade_requisitada,
						:quantidade_atendida,
						:estoque_id,
						:_destroy,
						:centro_de_custo_da_requisicao_id,
						:detalhamento_da_requisicao_de_material_id,
						demandas_programadas_attributes: [
							:id,
							:item_da_requisicao_de_material_id,
							:quantidade_requisitada,
							:quantidade_atendida,
							:data_do_atendimento,
							:_destroy
						]
					]
				)
		end

		def recusa_params
			params.require(:administrativo_requisicao_de_material).permit(:motivo_da_recusa).merge(status: 'recusado')
		end

		def devolucao_de_materiais_params
			params.require(:administrativo_requisicao_de_material).permit(:data_da_devolucao, :historico_da_devolucao).merge(status: 'devolvido_ao_almoxarifado')
		end
	end
end
