class Contabilidade::MovimentacoesDoPlanoDeContasController < ApplicationController
	include ContabilidadeControllerConcern
	include ControllerConcern
	include Contabilidade::MovimentacoesDoPlanoDeContasHelper

	before_action :authenticate_usuario!
	before_action :autoriza_usuario!
	before_action :disponibiliza_movimentacao_copia, only: [:new]
	before_action :disponibiliza_dependencias, only: [:index, :index_movimentacoes_manuais]
	before_action :set_movimentacao_do_plano_de_contas, only: [:show, :edit, :update, :destroy, :verifica_mes_bloqueado]
	before_action :disponibiliza_dependencias_formulario, only: [:new, :edit]
	# before_action -> {verifica_mes_bloqueado(@movimentacao_do_plano_de_contas)}, only: [:edit, :destroy]
	
	def index
		# para cada par de conta do evento são feitas duas movimentações, uma para cada conta.
		# por esse motivo, no espelho contábil basta mostrar uma movimentação do par de conta
		# no caso irei filtar somente pelas movimentações debito mas poderia ser somente os creditos
		@q = contabilidade_atual.movimentacoes_do_plano_de_contas.debito.order(data_de_lancamento: :desc).search(params[:q])
		session[:lancamento_manual] = nil
		
		if request.format.json? && !params[:busca_movimentacoes_do_orcamento].present?
			# aqui eu pego os creditos pois no form do empenho eu preciso salvar a movimentacao de credito para pegar a conta correta no lancamento do
			# pcasp
			subacao = Loa::Subacao.find_by(id: params[:subacao_id])
			ids_unidades_orcamentarias = subacao.unidade_orcamentaria.unidade_gestora.unidades_orcamentarias.pluck(:id)
			
			ransack_params = Hash.new
			if params[:q][:lancamento_manual_in].present?
				ransack_params["lancamento_manual"] = params[:lancamento_manual_in]
			end

			if params[:q][:sub_conta_pcasp_id_eq].present?
				sub_conta_codigo = Contabilidade::SubContaPcasp.find(params[:q][:sub_conta_pcasp_id_eq]).codigo
				sub_contas_com_mesmo_codigo = Contabilidade::SubContaPcasp.where(codigo: sub_conta_codigo).pluck(:id)
				ransack_params["sub_conta_pcasp_id_in"] = sub_contas_com_mesmo_codigo
			end

			@q = Contabilidade::MovimentacaoDoPlanoDeContas.joins(conta_por_evento_contabil: :conta).where("contabilidade_contas.codigo like '21%'").credito.where('unidade_orcamentaria_id in (?) AND lancamento_manual is NOT NULL', ids_unidades_orcamentarias).ransack(ransack_params)
			@todas_movimentacoes_do_plano_de_contas = @q.result(distinct: false)
			ids_movimentacoes_do_plano_de_contas = []
			@todas_movimentacoes_do_plano_de_contas.group_by{ |mov| mov.conta_por_evento_contabil.conta.codigo}.each do |conta, movimentacoes|
				ids_movimentacoes_do_plano_de_contas << movimentacoes.last.id
			end
			
			@movimentacoes_do_plano_de_contas = Contabilidade::MovimentacaoDoPlanoDeContas.where(id: ids_movimentacoes_do_plano_de_contas)
		elsif request.format.json? && params[:busca_movimentacoes_do_orcamento].present? && params[:busca_movimentacoes_do_orcamento] == "true"
			@q = contabilidade_atual.movimentacoes_do_plano_de_contas.order(data_de_lancamento: :desc).search(params[:q])

			@todas_movimentacoes_do_plano_de_contas = @q.result(distinct: false)
			ids_movimentacoes_do_plano_de_contas = []
			@todas_movimentacoes_do_plano_de_contas.group_by{ |mov| mov.conta_por_evento_contabil.conta.codigo}.each do |conta, movimentacoes|
				ids_movimentacoes_do_plano_de_contas << movimentacoes.last.id
			end
			
			@movimentacoes_do_plano_de_contas = Contabilidade::MovimentacaoDoPlanoDeContas.where(id: ids_movimentacoes_do_plano_de_contas)
		else
			@q = contabilidade_atual.movimentacoes_do_plano_de_contas.debito.order(data_de_lancamento: :desc).search(params[:q])
			@movimentacoes_do_plano_de_contas = @q.result(distinct: false).paginate(page: params[:page], per_page: 20)
		end

		respond_to do |format|
			format.html
			format.json { render json: @movimentacoes_do_plano_de_contas, methods: :conta_pcasp_passivo }
		end
	end

	def index_movimentacoes_manuais
		session[:lancamento_manual] = params[:lancamento_manual]

		@q = contabilidade_atual.movimentacoes_do_plano_de_contas.where(lancamento_manual: session[:lancamento_manual]).order(data_de_lancamento: :desc).search(params[:q])

		@movimentacoes_do_plano_de_contas = @q.result(distinct: true).paginate(page: params[:page], per_page: 20)
		@grupos_de_eventos = Contabilidade::GrupoDeEventoContabil.where(lancamento_manual: session[:lancamento_manual])
		@eventos_contabeis = contexto_atual.eventos_contabeis.joins(:grupo_de_evento_contabil).where(
			contabilidade_grupo_de_eventos_contabeis: {
				lancamento_manual: Contabilidade::GrupoDeEventoContabil.lancamentos_manuais[session[:lancamento_manual]]
				}
			)

		render :index
	end

	def show
		if @movimentacao_do_plano_de_contas.nil?
			redirect_to contabilidade_index_movimentacoes_manuais_path(lancamento_manual: session[:lancamento_manual]), alert: 'Movimentação não existe'
		end
	end

	def new
		session[:lancamento_manual] = params[:lancamento_manual]

		@movimentacao_do_plano_de_contas = Contabilidade::MovimentacaoDoPlanoDeContas.new
		duplicar_movimentacao if params[:duplicar_id]
	end

	def duplicar_movimentacao
		return unless @movimentacao_original

		@movimentacao_do_plano_de_contas = @movimentacao_original.dup
		@movimentacao_do_plano_de_contas.tipo_de_lancamento = Contabilidade::MovimentacaoDoPlanoDeContas.tipo_de_lancamentos[:debito]
	end

	def disponibiliza_movimentacao_copia
		return unless params[:duplicar_id]
		@movimentacao_original = Contabilidade::MovimentacaoDoPlanoDeContas.find(params[:duplicar_id])
	end

	def new_por_gerador
		@movimentacao_do_plano_de_contas = Contabilidade::MovimentacaoDoPlanoDeContas.new(
			gerador_id: params[:gerador_id],
			gerador_type: params[:gerador_type]
		)

		disponibiliza_dependencias_contas
		@eventos_contabeis = []
		
		if @movimentacao_do_plano_de_contas.gerador.present? && @movimentacao_do_plano_de_contas.gerador.try(:natureza_da_receita).try(:present?)
			if @movimentacao_do_plano_de_contas.gerador.natureza_da_receita.categoria_economica == "002" and @movimentacao_do_plano_de_contas.gerador.natureza_da_receita.origem == "1"
				@subcontas_pcasp = Contabilidade::SubContaPcasp.where(topico_da_conta: 'operacao_de_credito', data_de_inativacao: nil, orcamento: contexto_atual).all rescue []
			elsif @movimentacao_do_plano_de_contas.gerador.natureza_da_receita.detalhamento_optativo == "3"
				@subcontas_pcasp = Contabilidade::SubContaPcasp.where(topico_da_conta: 'divida_ativa', data_de_inativacao: nil, orcamento: contexto_atual).all rescue []
			end
		end
	end

	def create_por_gerador
		@movimentacao_do_plano_de_contas = Contabilidade::MovimentacaoDoPlanoDeContas.new(movimentacao_do_plano_de_contas_params)
		ActiveRecord::Base.transaction do
			if @movimentacao_do_plano_de_contas.save && @movimentacao_do_plano_de_contas.gera_movimentacao_creditos		
				redirect_to rota_do_gerador(@movimentacao_do_plano_de_contas), notice: 'Movimentação gerada com sucesso'
			else
				disponibiliza_dependencias_contas
				tipo_debito = Contabilidade::MovimentacaoDoPlanoDeContas.tipo_de_lancamentos[:debito]
				tipo_credito = Contabilidade::MovimentacaoDoPlanoDeContas.tipo_de_lancamentos[:credito]

				@eventos_contabeis = contexto_atual.eventos_contabeis.joins(sql_joins_por_contas).where(sql_filtro_por_contas, tipo_debito, @movimentacao_do_plano_de_contas.conta_debito_id, tipo_credito, @movimentacao_do_plano_de_contas.conta_credito_id).distinct
				flash.now[:alert] = "A movimentação do plano de contas não pode ser salva, verifique as informações"
				render :new_por_gerador
				raise ActiveRecord::Rollback
			end
		end
	end

	def create
		atributos_da_movimentacao = movimentacao_do_plano_de_contas_params

		if atributos_da_movimentacao[:categoria_de_lancamento].present?
			atributos_da_movimentacao[:categoria_de_lancamento] = atributos_da_movimentacao[:categoria_de_lancamento]&.to_i rescue nil
		end

		if atributos_da_movimentacao[:titulo].present?
			atributos_da_movimentacao[:titulo] = atributos_da_movimentacao[:titulo]&.to_i rescue nil
		end

		@movimentacao_do_plano_de_contas = Contabilidade::MovimentacaoDoPlanoDeContas.new(atributos_da_movimentacao)


		if @movimentacao_do_plano_de_contas.mes_bloqueado?
			verifica_mes_bloqueado(@movimentacao_do_plano_de_contas)
			return
		end

		if @movimentacao_do_plano_de_contas.data_de_lancamento.year != contexto_atual.exercicio
			flash.now[:alert] = "O exercicio do lançamento manual é: #{@movimentacao_do_plano_de_contas.data_de_lancamento.year} e difere do orçamento atual: #{contexto_atual.exercicio}"
			disponibiliza_dependencias_formulario
			render :new
			return
		end

		if atributos_da_movimentacao[:criar_nova_subconta] == '1'
			divida_consolidada = params[:divida_consolidada].present?
			sub_conta_pcasp = Contabilidade::SubContaPcasp.create(
				descricao: atributos_da_movimentacao[:descricao_subconta],
				topico_da_conta: session[:lancamento_manual],
				divida_consolidada: divida_consolidada,
				titulo: atributos_da_movimentacao[:titulo].present? ? atributos_da_movimentacao[:titulo] : nil
			)

			@movimentacao_do_plano_de_contas.sub_conta_pcasp_id = sub_conta_pcasp.id
		end

		if @movimentacao_do_plano_de_contas.save
			redirect_to contabilidade_movimentacao_do_plano_de_contas_path(@movimentacao_do_plano_de_contas)
		else
			disponibiliza_dependencias_formulario
			render :new
		end
	end

	def edit
	end

	def update
		atributos_da_movimentacao = movimentacao_do_plano_de_contas_params

		if atributos_da_movimentacao[:categoria_de_lancamento].present?
			atributos_da_movimentacao[:categoria_de_lancamento] = atributos_da_movimentacao[:categoria_de_lancamento]&.to_i rescue nil
		end

		if atributos_da_movimentacao[:titulo].present?
			atributos_da_movimentacao[:titulo] = atributos_da_movimentacao[:titulo]&.to_i rescue nil
		end

		if atributos_da_movimentacao[:criar_nova_subconta] == '1'
			sub_conta_pcasp = Contabilidade::SubContaPcasp.create(
				descricao: atributos_da_movimentacao[:descricao_subconta],
				topico_da_conta: session[:lancamento_manual],
				titulo: atributos_da_movimentacao[:titulo].present? ? atributos_da_movimentacao[:titulo] : nil
			)

			atributos_da_movimentacao[:sub_conta_pcasp_id] = sub_conta_pcasp.id
		end

		if @movimentacao_do_plano_de_contas.update(atributos_da_movimentacao)
			redirect_to @movimentacao_do_plano_de_contas, notice: 'Atualizado com sucesso'
		else
			disponibiliza_dependencias
			disponibiliza_dependencias_formulario
			render :edit
		end
	end

	def destroy
		mensagem = apaga_e_retorna_mensagem(@movimentacao_do_plano_de_contas)
		if @movimentacao_do_plano_de_contas.errors.present?
			redirect_to @movimentacao_do_plano_de_contas, alert: "#{@movimentacao_do_plano_de_contas.errors.messages.values.join(', ')}"
		else
			redirect_to contabilidade_index_movimentacoes_manuais_path(lancamento_manual: session[:lancamento_manual]), notice: "#{mensagem.values.join(", ")}"
		end
		# if @movimentacao_do_plano_de_contas.gerador_type == 'Contabilidade::Empenho'
		# 	redirect_to empenho_path(@movimentacao_do_plano_de_contas.gerador)
		# elsif @movimentacao_do_plano_de_contas.gerador_type == 'Loa::OrcamentoDaReceita'
		# 	redirect_to base_natureza_da_receita_path(@movimentacao_do_plano_de_contas.gerador.natureza_da_receita)
		# else
		# 	if @movimentacao_do_plano_de_contas.gerador_type == 'Contabilidade::Empenho'
		# 		redirect_to empenho_path(@movimentacao_do_plano_de_contas.gerador), notice: 'Movimentação deletada com sucesso'
		# 	else
		# 		if @movimentacao_do_plano_de_contas.gerador_type == "Contabilidade::SituacaoDaObra"
		# 			redirect_to @movimentacao_do_plano_de_contas.gerador.obra, notice: 'Movimentação deletada com sucesso'
		# 		else
		# 			redirect_to @movimentacao_do_plano_de_contas.gerador, notice: 'Movimentação deletada com sucesso'
		# 		end
		# 	end
		# end
	end

	private
	def disponibiliza_dependencias
		@tipos_de_movimentacoes = Contabilidade::MovimentacaoDoPlanoDeContas.tipos_de_movimentacoes
		@subcontas_pcasp = Contabilidade::SubContaPcasp.where(topico_da_conta: session[:lancamento_manual], orcamento: contexto_atual).all
	end

	def disponibiliza_dependencias_contas
		@contas = contexto_atual.contas.analiticas.order(codigo: :asc)
	end

	def disponibiliza_dependencias_formulario
		if session[:lancamento_manual] == "precatorio"
			@grupos_de_eventos = Contabilidade::GrupoDeEventoContabil.where(categoria_de_lancamento: @movimentacao_do_plano_de_contas.categoria_de_lancamento, lancamento_manual: session[:lancamento_manual]).where("titulo IS NOT null") rescue []
		else
			@grupos_de_eventos = Contabilidade::GrupoDeEventoContabil.where(categoria_de_lancamento: @movimentacao_do_plano_de_contas.categoria_de_lancamento, lancamento_manual: session[:lancamento_manual]).where("titulo IS NOT null") rescue []
		end
		if session[:lancamento_manual] != nil
			@grupos_de_eventos = Contabilidade::GrupoDeEventoContabil.where(categoria_de_lancamento: @movimentacao_do_plano_de_contas.categoria_de_lancamento, lancamento_manual: session[:lancamento_manual]) rescue []
		else
			@grupos_de_eventos = Contabilidade::GrupoDeEventoContabil.where(categoria_de_lancamento: @movimentacao_do_plano_de_contas.categoria_de_lancamento) rescue []
		end

		@eventos_contabeis = contexto_atual.eventos_contabeis.where(grupo_de_evento_contabil_id: @grupos_de_eventos.ids) rescue []
		@centros_de_custo = Controladoria::CentroDeCusto.where(unidade_gestora_id: @movimentacao_do_plano_de_contas.unidade_orcamentaria.unidade_gestora_id) rescue []
		@contas_bancarias = Base::ContaBancaria.where("data_de_inativacao >= ? OR data_de_inativacao is null", Date.today).left_outer_joins(agencia: :banco).includes(agencia: :banco).all.order(conta_caixa_pcasp: :desc, sigla: :asc, numero_da_conta: :asc)
		@contas_extra_orcamentarias = contexto_atual.contas_extra_orcamentarias

		categorias_de_lancamento_i18n = Contabilidade::GrupoDeEventoContabil.categorias_de_lancamento_i18n.transform_keys{|key| Contabilidade::GrupoDeEventoContabil.categorias_de_lancamento[key]}
		if session[:lancamento_manual] == 'almoxarifado' || session[:lancamento_manual] == 'rpps' || session[:lancamento_manual] == 'provisoes' || session[:lancamento_manual] == 'imobilizado'
			@categorias_de_lancamento = categorias_de_lancamento_i18n.reject { |key| key == 3 || key == 4 }
		elsif session[:lancamento_manual] == 'abertura'
			@categorias_de_lancamento = categorias_de_lancamento_i18n.reject { |key| key == 2 || key == 3 || key == 4 }
		elsif session[:lancamento_manual] == 'investimentos'
			@categorias_de_lancamento = categorias_de_lancamento_i18n.reject { |key| key == 3 || key == 4 }
		else
			@categorias_de_lancamento = categorias_de_lancamento_i18n
		end

		if params[:duplicar_id].present?
			categoria = Contabilidade::MovimentacaoDoPlanoDeContas.categorias_de_lancamento[@movimentacao_original.categoria_de_lancamento]
			unless @categorias_de_lancamento.include? categoria
				@categorias_de_lancamento[categoria] = @movimentacao_original.categoria_de_lancamento_i18n
			end
		end

		@unidades_orcamentarias = contexto_atual.unidades_orcamentarias

		if session[:lancamento_manual] == 'abertura'
			@subcontas_pcasp = Contabilidade::SubContaPcasp.where(data_de_inativacao: nil, orcamento: contexto_atual).all
		else
			@subcontas_pcasp = Contabilidade::SubContaPcasp.where(topico_da_conta: session[:lancamento_manual], data_de_inativacao: nil, orcamento: contexto_atual).all
		end

		# dependencias dos ics
		@fontes_de_recursos = contexto_atual.fontes_de_recursos.all
		@naturezas_da_receita = contexto_atual.naturezas_da_receita.where(analitica: true).all.order(:codigo)
		@sub_elementos_de_despesa = Contabilidade::SubElementoDeDespesa
			.joins(elemento_de_despesa: [modalidade_de_aplicacao: [grupo_de_natureza_da_despesa: :categoria_economica]])
			.includes(elemento_de_despesa: [modalidade_de_aplicacao: [grupo_de_natureza_da_despesa: :categoria_economica]])
			.where(base_categorias_economicas: {modulo_id: contexto_atual.id}).all
		@funcoes_e_subfuncoes = contexto_atual.subfuncoes.all
	end

	def set_movimentacao_do_plano_de_contas
		@movimentacao_do_plano_de_contas = Contabilidade::MovimentacaoDoPlanoDeContas.find_by(id: params[:id])
	end

	def movimentacao_do_plano_de_contas_params
		params.require(:contabilidade_movimentacao_do_plano_de_contas).permit(
			:data_de_lancamento, :lancamento_manual, :exercicio, :unidade_orcamentaria_id, :categoria_de_lancamento,
			:titulo, :grupo_de_evento_id, :valor, :evento_contabil_id, :historico, :numero_do_processo_judicial, :conta_bancaria_id,
			:conta_debito_id, :conta_credito_id, :gerador_id, :gerador_type, :codigo_subconta, :centro_de_custo_id, :criar_nova_subconta, 
			:descricao_subconta, :conta_extra_orcamentaria_id, :sub_conta_pcasp_id, :ic_fp, :fonte_de_recursos_id, :ic_nd, :ic_nr, :ic_fs,
			:ic_fp_credito, :ic_nr_credito, :ic_nd_credito, :ic_fs_credito, :fonte_de_recursos_credito_id
		)
	end

	def sql_filtro_por_contas
		'(conta_debito.tipo_de_lancamento = ?
		AND conta_debito.conta_id = ?)
		AND (conta_credito.tipo_de_lancamento = ?
		AND conta_credito.conta_id = ?)'
	end

	def sql_joins_por_contas
		'INNER JOIN contabilidade_contas_por_eventos_contabeis AS conta_credito ON contabilidade_eventos_contabeis.id = conta_credito.evento_contabil_id 
		INNER JOIN contabilidade_contas_por_eventos_contabeis AS conta_debito ON contabilidade_eventos_contabeis.id = conta_debito.evento_contabil_id'
	end
end
