module Contabilidade
	class AnulacoesDoEmpenhoController < ApplicationController
		include ControllerConcern
		include AnulacoesDoEmpenhoHelper

		before_action -> { verifica_modulo_na_sessao(["administrativo", "contabilidade", "controladoria"]) }
		before_action :authenticate_usuario!
		before_action :autoriza_usuario!, except: [:enviar_para_administrativo, :editar_itens, :atualizar_itens, :retornar_para_solicitado]
		before_action :set_empenho, only: [:new, :create]
		before_action :set_anulacao_do_empenho, except: [:index, :new, :create, :receber_varios_itens, :confirmar_varios_itens]
		before_action :define_modulo_atual
		before_action -> {verifica_mes_bloqueado(@anulacao_do_empenho) if @anulacao_do_empenho.confirmado?}, only: [:edit, :destroy, :retornar_para_solicitado]
		before_action -> {verifica_mes_bloqueado(@anulacao_do_empenho)}, only: [:confirmar_anulacao]
		def index
			@q =
				if params[:a_receber].present?
					@url_anulacoes = a_receber_contabilidade_anulacoes_do_empenho_path
					@action_anulacoes_do_empenho = "a_receber"
					contexto_atual.anulacoes_do_empenho.enviado_para_contabilidade.search(params[:q])
				elsif params[:em_analise].present?
					@url_anulacoes = em_analise_contabilidade_anulacoes_do_empenho_path
					@action_anulacoes_do_empenho = "em_analise"
					contexto_atual.anulacoes_do_empenho.em_analise.search(params[:q])
				elsif params[:a_confirmar].present?
					@url_anulacoes = a_confirmar_contabilidade_anulacoes_do_empenho_path
					@action_anulacoes_do_empenho = "a_confirmar"
					contexto_atual.anulacoes_do_empenho.recebido.search(params[:q])
				else
					@url_anulacoes = contabilidade_anulacoes_do_empenho_path
					@action_anulacoes_do_empenho = ""
					contexto_atual.anulacoes_do_empenho.search(params[:q])
				end
			@pessoas = Base::Pessoa.includes(:tipo_de_pessoa).order(:nome)
			@modelo_anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.new
			@unidades_orcamentarias = contexto_atual.unidades_orcamentarias
			@anulacoes_do_empenho = @q.result(distinct: false).paginate(page: params[:page], per_page: 10)
		end

		def show
			@anulacao_do_empenho.logado_na_contabilidade = true if logado_na_contabilidade?
			@anulacao_do_empenho.logado_no_administrativo = true if logado_no_administrativo?
		end

		# GET /contabilidade/empenhos/1/anulacoes_do_empenho/new
		def new
			@anulacao_do_empenho = @empenho.anulacoes_do_empenho.new
			@anulacao_do_empenho.tipo_de_anulacao = Contabilidade::AnulacaoDoEmpenho.tipos_de_anulacao[params[:tipo]]

			mensagem = if !@empenho.confirmado?
				'Este empenho ainda não está confirmado, não é possivel anular'
			elsif @empenho.data_do_empenho == Date.today && @empenho.solicitado?
				'Este empenho foi lançado hoje, ao invés de anulado, deve ser excluído.'
			else
				if @empenho.saldo > 0
					'Selecione um tipo anulação válida.' unless params[:tipo]
				else
					'Empenho não possui saldo.'
				end
			end

			redirect_to empenho_path(@empenho) + "?tab=anulacoes", alert: mensagem if mensagem

			if @anulacao_do_empenho.tipo_de_anulacao == "total" || (params[:todos] == 'true')
				@anulacao_do_empenho.valor = @empenho.saldo
				@itens_do_empenho.each do |ie|
					if ie.quantidade_disponivel_a_liquidar > 0
						@anulacao_do_empenho.itens_anulados.build(quantidade: ie.quantidade_disponivel_a_liquidar, item_do_empenho: ie)
					end
				end
			elsif @anulacao_do_empenho.itens_anulados.empty?
				@anulacao_do_empenho.itens_anulados.build
			end
		end

		# POST /contabilidade/empenhos/1/anulacoes_do_empenho
		def create
			@anulacao_do_empenho = @empenho.anulacoes_do_empenho.new(anulacao_do_empenho_params)
			@anulacao_do_empenho.status = Contabilidade::AnulacaoDoEmpenho.status["solicitado"]
			@anulacao_do_empenho.modulo_atual = session[:modulo]
			
			if @anulacao_do_empenho.save
				@empenho.anular! if logado_na_contabilidade?
				if params[:anulacao_para_relancamento] == "true" && @anulacao_do_empenho.valid?
					mensagem = 'Anulação do empenho foi criada com sucesso. Cadastre agora o relançamento do empenho antigo.'
					redirect_to new_empenho_path(exercicio: contexto_atual.exercicio, atributos_para_relancamento: @empenho.attributes.except!(:created_at), atributos_da_anulacao: anulacao_do_empenho_params), notice: mensagem
				else
					redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho.id), notice: 'Anulação do empenho foi criada com sucesso.'
				end
			else
				@empenho = @anulacao_do_empenho.empenho
				flash.now[:alert] = 'Não foi possível criar a anulação do empenho, verifique os erros.'
				render :new
			end
		end

		# GET /contabilidade/anulacoes_do_empenho/1/edit
		def edit
			@itens_do_empenho = @anulacao_do_empenho.empenho.itens_do_empenho
			@empenho = @anulacao_do_empenho.empenho
			if @anulacao_do_empenho.confirmado?
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), alert: 'Esta anulação não pode ser mais editada.'
			end
		end

		# Testar método
		# PATCH/PUT /contabilidade/anulacoes_do_empenho/1
		def update
			if @anulacao_do_empenho.update( anulacao_do_empenho_params )
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho.id), success: 'Anulação foi atualizada com sucesso.'
			else
				@itens_do_empenho = @anulacao_do_empenho.empenho.itens_do_empenho
				@empenho = @anulacao_do_empenho.empenho
				render :edit
			end
		end

		# Testar método
		# DELETE /contabilidade/anulacoes_do_empenho/1
		def destroy
			@empenho = @anulacao_do_empenho.empenho
			mensagem = apaga_e_retorna_mensagem(@anulacao_do_empenho)
			if @empenho.anulado?
				@empenho.confirmar!
			end
			redirect_to empenho_path(@empenho) + "?tab=anulacoes", mensagem
		end

		# PATCH /administrativo/anulacoes_do_empenho/1/enviar_para_controladoria
		def enviar_para_controladoria
			if @anulacao_do_empenho.enviar_para_controladoria!
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), success: 'A Anulação do Empenho foi enviada para a controladoria com sucesso'
			else
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), alert: 'Não foi possível encaminhar a Anulação. Por favor, confira se ela contém erros'
			end
		end

		# PATCH /controladoria/anulacoes_do_empenho/1/enviar_para_contabilidade
		def enviar_para_contabilidade
			if @anulacao_do_empenho.enviar_para_contabilidade!
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), success: 'A anulação do Empenho foi enviada para a contabilidade com sucesso'
			else
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), alert: 'Não foi possível encaminhar a Anulação. Por favor, confira se ela contém erros'
			end
		end

		# PATCH /controladoria/anulacoes_do_empenho/1/enviar_para_administrativo
		def enviar_para_administrativo
			if @anulacao_do_empenho.enviar_para_administrativo!
				redirect_to controladoria_anulacoes_do_empenho_path, success: 'A anulação do Empenho foi enviada para a contabilidade com sucesso'
			else
				redirect_to controladoria_anulacoes_do_empenho_path(@anulacao_do_empenho), alert: 'Não foi possível encaminhar a Anulação. Por favor, confira se ela contém erros'
			end
		end

		# PATCH /controladoria/anulacoes_do_empenho/1/retornar_para_administrativo
		def retornar_para_administrativo
			if @anulacao_do_empenho.retornar_para_administrativo!
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), success: 'A anulação foi enviado para a administração para correção dos erros'
			else
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), alert: 'Não foi possível encaminhar a Anulação. Por favor, confira se ela contém erros'
			end
		end

		# PATCH /administrativo/anulacoes_do_empenho/1/confirmar_anulacao
		def confirmar_anulacao
			if @anulacao_do_empenho.confirmar!
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), success: 'A Anulação do Empenho foi confirmada com sucesso'
			else
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), alert: 'Não foi possível confimar a anulação. Por favor, confira se ela contém erros'
			end
		end

		# PATCH /anulacoes_do_empenho/:id/receber_anulacao
		def receber_anulacao
			if @anulacao_do_empenho.receber!
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), success: 'A Anulação do Empenho foi recebida com sucesso'
			else
				redirect_to contabilidade_anulacao_do_empenho_path(@anulacao_do_empenho), alert: 'Não foi possível receber a anulação. Por favor, confira se ela contém erros'
			end
		end

		#POST /anulacoes_do_empenho/receber_varios_itens
		def receber_varios_itens
			anulacoes_do_empenho = params[:contabilidade_anulacao_do_empenho]
			recebidas = Array.new
			erros = Set.new
			quantidade_enviada = 0
			ActiveRecord::Base.transaction do
				anulacoes_do_empenho.each do |chave, valor|
					if valor.to_i == 1
						quantidade_enviada += 1
						if Contabilidade::AnulacaoDoEmpenho.find(chave.to_s.to_i).receber!
							recebidas << chave.to_s.to_i
						else
							estorno_de_liquidacao.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 a_receber_contabilidade_anulacoes_do_empenho_path, alert: "Nenhuma Anulação do Empenho foi recebida"
				else
					redirect_to a_receber_contabilidade_anulacoes_do_empenho_path, alert: "Falha ao receber Anulação do Empenho: #{erros.to_a.join(', ')}"
				end
			elsif recebidas.size == 1
				redirect_to anulacao_do_empenho_path(recebidas[0]), success: "Anulação do Empenho recebida com sucesso"
			else
				redirect_to a_receber_contabilidade_anulacoes_do_empenho_path, success: "Todas #{recebidas.size} Anulações de Empenho foram recebidas com sucesso"
			end
		end

		#POST /anulacoes_do_empenho/confirmar_varios_itens
		def confirmar_varios_itens
			anulacoes_do_empenho = params[:contabilidade_anulacao_do_empenho]
			confirmados = Array.new
			erros = Set.new
			quantidade_enviada = 0
			ActiveRecord::Base.transaction do
				anulacoes_do_empenho.each do |chave, valor|
					if valor.to_i == 1
						quantidade_enviada += 1
						if Contabilidade::AnulacaoDoEmpenho.find(chave.to_s.to_i).confirmar!
							confirmados << chave.to_s.to_i
						else
							estorno_de_liquidacao.errors.full_messages.each do |erro|
								erros << erro
							end
							raise ActiveRecord::Rollback
						end
					end
				end
			end

			if confirmados.size == 0
				if erros.size == 0
					redirect_to a_confirmar_contabilidade_anulacoes_do_empenho_path, alert: "Nenhuma Anulação do Empenho foi confirmado"
				else
					redirect_to a_confirmar_contabilidade_anulacoes_do_empenho_path, alert: "Falha ao receber Anulação do Empenho: #{erros.to_a.join(', ')}"
				end
			elsif confirmados.size == 1
				redirect_to anulacao_do_empenho_path(confirmados[0]), success: "Anulação do Empenho comfirmada com sucesso"
			else
				redirect_to a_confirmar_contabilidade_anulacoes_do_empenho_path, success: "Todas #{confirmados.size} Anulações de Empenho foram confirmadas com sucesso"
			end
		end

		def retornar_para_solicitado
			if @anulacao_do_empenho.retornar_para_solicitado!
				redirect_to @anulacao_do_empenho, success: "Retornado para solicitado com sucesso"
			else
				redirect_to @anulacao_do_empenho, alert: "Não foi possivel retornar para solicitado"
			end
		end

		def editar_itens
			@itens_da_anulacao = @anulacao_do_empenho.itens_anulados.includes(:item_do_empenho).order("item_do_empenho_id ASC").paginate(page: params[:page], per_page: 30)
		end

		def atualizar_itens
			if @anulacao_do_empenho.update(anulacao_do_empenho_params)
				respond_to do |format|
					format.json {render json: true}
				end
			else
				respond_to do |format|
					anulacao_do_empenho = @anulacao_do_empenho.errors.to_hash
					id_dos_itens = anulacao_do_empenho_params[:itens_anulados_attributes].values.map { |item_anulado| item_anulado[:id] }
					itens_invalidos = @anulacao_do_empenho.itens_anulados.select { |item| id_dos_itens.include?(item.id.to_s) && item.invalid? }
					json_errors = {}

					itens_invalidos.each do |item_invalido|
						json_errors[item_invalido.id.to_s.to_sym] = item_invalido.errors.to_hash
					end

					json_errors[0] = anulacao_do_empenho

					format.json {render json: json_errors}
				end
			end
		end

		private
		def set_empenho
			@empenho = Empenho.find(params[:empenho_id])
			@itens_do_empenho = @empenho.itens_do_empenho
		end

		def set_anulacao_do_empenho
			@anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.find(params[:id])
		end

		def define_modulo_atual
			@anulacao_do_empenho.modulo_atual = session[:modulo] if @anulacao_do_empenho.present?
		end

		# Permite apenas os parâmetros específicos
		def anulacao_do_empenho_params
			params.require(:contabilidade_anulacao_do_empenho).permit(
				:empenho_id, :numero, :data_da_anulacao, :tipo_de_anulacao, :valor, :historico, :indisponibilidade_de_caixa, :retificadora,
				itens_anulados_attributes: [:id, :quantidade, :total, :item_do_empenho_id, :_destroy]
			)
		end
	end
end
