require 'active_support/concern'

module Tcm::BalancetePcasp extend ActiveSupport::Concern
	# BC_____.BAL
	# ARQUIVO 305

	def todas_as_movimentacoes_pcasp
		movimentacoes = Contabilidade::MovimentacaoDoPlanoDeContas.joins(unidade_orcamentaria: :tipo_de_unidade_administrativa).sem_encerramento.where(
			"(codigo_da_conta LIKE ANY (array['1________', '2________', '3________', '4________', '7________', '8________']))
			AND codigo_da_conta not in ('111110100', '111110200', '111110602', '111110603', '111110604', '111111900')
			AND contabilidade_movimentacoes_do_plano_de_contas.data_de_lancamento <= ?
			AND extract(year from data_de_lancamento) = ?
			AND base_tipos_de_unidades_administrativas.poder_associado = ?", self.lote.data_referencia.end_of_month, self.lote.data_referencia.year, self.lote.poder_associado
		)

		return movimentacoes
	end

	def gerar_balancetes_das_contas_pcasp
		self.carrega_dependencias_para_balancetes

		todas_as_movimentacoes_ate_o_mes = self.todas_as_movimentacoes_pcasp

		movimentacoes_bancarias = todas_as_movimentacoes_ate_o_mes.includes(:unidade_orcamentaria).map { |i|
			{
				id: i.id,
				codigo_da_conta: i.codigo_da_conta,
				data_de_lancamento: i.data_de_lancamento,
				valor: i.valor,
				tipo_de_lancamento: i.tipo_de_lancamento,
				unidade_gestora_id: i.unidade_orcamentaria.unidade_gestora_id,
				conta_bancaria_id: i.conta_bancaria_id,
				fonte_de_recursos_id: i.fonte_de_recursos_id,
				codigo_completo_fr: i.codigo_completo_fr,
				poder_associado: i.unidade_orcamentaria.tipo_de_unidade_administrativa.poder_associado,
				ic_nr: i.ic_nr,
				lancamento_manual: i.lancamento_manual
			}
		}

		conteudo = ""
		todas_as_movimentacoes_ate_o_mes.group_by{ |movimentacao|
			[
				movimentacao.codigo_da_conta,
				movimentacao.unidade_orcamentaria.unidade_gestora_id,
				movimentacao.codigo_superavit_financeiro,
				movimentacao.codigo_completo_fr
			]
		}.each do |criterios, movimentacoes|
			codigo_da_conta = criterios[0]
			conta = @contas.select{ |i| i[:codigo] == codigo_da_conta}.first
			unidade_gestora_id = criterios[1]
			codigo_completo_fr = criterios[3]

			movimentacoes_dos_balancetes = @movimentacoes_das_contas_do_balancete.select { |i| movimentacoes.map(&:id).include?(i[:movimentacao_do_plano_de_contas_id])}
			movimentacoes_dos_balancetes_cb = @movimentacoes_das_contas_do_balancete.select { |i| i[:conta_bancaria_id].present? && movimentacoes.map(&:id).include?(i[:movimentacao_do_plano_de_contas_id])}

			saldo_debito_total = movimentacoes_dos_balancetes.select { |i| i[:tipo_de_lancamento] == "debito" && i[:lancamento_manual] != 'abertura' && i[:lancamento_manual] != 'encerramento' }.map { |i| i[:valor] }.sum.to_d
			saldo_credito_total = movimentacoes_dos_balancetes.select { |i| i[:tipo_de_lancamento] == "credito" && i[:lancamento_manual] != 'abertura' && i[:lancamento_manual] != 'encerramento' }.map { |i| i[:valor] }.sum.to_d
			saldo_de_debito_contas_bancarias = movimentacoes_dos_balancetes_cb.select { |i| i[:tipo_de_lancamento] == "debito" && i[:lancamento_manual] != 'abertura' && i[:lancamento_manual] != 'encerramento' }.map { |i| i[:valor] }.sum.to_d
			saldo_de_creditos_contas_bancarias = movimentacoes_dos_balancetes_cb.select { |i| i[:tipo_de_lancamento] == "credito" && i[:lancamento_manual] != 'abertura' && i[:lancamento_manual] != 'encerramento' }.map { |i| i[:valor] }.sum.to_d

			saldo_inicial_do_mes = Contabilidade::BalanceteDeVerificacao.saldo_inicial_do_balancete_por_hash(conta, movimentacoes_bancarias, self.lote.data_referencia.end_of_month, unidade_gestora_id, self.lote.poder_associado, nil, nil, nil, codigo_completo_fr).to_d

			args = {
				conta: conta,
				mes_de_referencia: read_attribute_before_type_cast(:mes_de_referencia),
				unidade_gestora_id: criterios[1],
				codigo_superavit: criterios[2],
				fonte_de_recursos: criterios[3],
				saldo_debito_total: saldo_debito_total,
				saldo_credito_total: saldo_credito_total,
				saldo_de_debito_contas_bancarias: saldo_de_debito_contas_bancarias,
				saldo_de_creditos_contas_bancarias: saldo_de_creditos_contas_bancarias,
				saldo_inicial_do_mes: saldo_inicial_do_mes
			}

			if saldo_debito_total != 0 || saldo_credito_total != 0 || saldo_de_debito_contas_bancarias != 0 || saldo_de_creditos_contas_bancarias != 0 || saldo_inicial_do_mes != 0
				conteudo << self.to_sim_pcasp(args)
				conteudo << "\r\n"
			end

		end
		self.update_column(:conteudo, conteudo)
	end

	def carrega_dependencias_para_balancetes
		@configuracao = Configuracao.first
		@orcamento = self.lote.orcamento.attributes.symbolize_keys
		@contas = Contabilidade::Conta.where(orcamento_id: @orcamento[:id]).all.map { |i| { id: i.id, natureza_do_saldo: i.natureza_do_saldo, codigo: i.codigo, saldo_inicial: i.saldo_inicial, subtitulo: i.subtitulo } }

		@unidades_gestoras = Loa::UnidadeGestora.all.map { |i|
			{
				id: i.id,
				codigo: i.codigo,
				nome: i.nome
			}
		}

		@contas_bancarias = Base::ContaBancaria.all.where("agencia_id is not null").includes(:agencia).map { |i|
			{
				id: i.id,
				numero_da_conta: i.numero_da_conta,
				numero_da_agencia: i.agencia.numero_da_agencia,
				numero_do_banco: i.agencia.banco.numero_do_banco
			}
		}

		@movimentacoes_das_contas_do_balancete = Contabilidade::MovimentacaoDaContaDoBalancete
				.joins(movimentacao_do_plano_de_contas: [unidade_orcamentaria: :tipo_de_unidade_administrativa])
				.where("(codigo_da_conta LIKE ANY (array['1________', '2________', '3________', '4________', '7________', '8________']))
					AND codigo_da_conta not in ('111110100', '111110200', '111110602', '111110603', '111110604', '111111900')
					AND contabilidade_movimentacoes_do_plano_de_contas.data_de_lancamento between ? and ?
					AND extract(year from data_de_lancamento) = ?
					AND base_tipos_de_unidades_administrativas.poder_associado = ?", self.lote.data_referencia, self.lote.data_referencia.end_of_month, self.lote.data_referencia.year, self.lote.poder_associado)
				.where("coalesce(contabilidade_movimentacoes_do_plano_de_contas.lancamento_manual, 0) != 1000")
			.includes(:movimentacao_do_plano_de_contas).map{ |i| {
					id: i.id,
					movimentacao_do_plano_de_contas_id: i.movimentacao_do_plano_de_contas_id,
					data_de_lancamento: i.movimentacao_do_plano_de_contas.data_de_lancamento,
					lancamento_manual: i.movimentacao_do_plano_de_contas.lancamento_manual,
					tipo_de_lancamento: i.movimentacao_do_plano_de_contas.tipo_de_lancamento,
					valor: i.movimentacao_do_plano_de_contas.valor
				}
			}
	end

	def to_sim_pcasp(args)
		begin
			texto = ""
			data_inicial = Date.new(@orcamento[:exercicio], Tcm::Lote.mes_de_referencias[self.lote.mes_de_referencia])
			data_final = data_inicial.end_of_month

			unidade_gestora = @unidades_gestoras.select{|i| i[:id] == args[:unidade_gestora_id]}.first

			saldo_inicial_do_mes = args[:saldo_inicial_do_mes]

			if args[:conta][:natureza_do_saldo] == "credor" || args[:conta][:natureza_do_saldo] == "mista"
				saldo_final_do_mes = saldo_inicial_do_mes - args[:saldo_debito_total] + args[:saldo_credito_total]
				tipo_do_saldo_incial = (saldo_inicial_do_mes >= 0 ? 'C' : 'D')
				tipo_do_saldo_final = (saldo_final_do_mes >= 0 ? 'C' : 'D')
			else
				saldo_final_do_mes = saldo_inicial_do_mes + args[:saldo_debito_total] - args[:saldo_credito_total]
				tipo_do_saldo_incial = (saldo_inicial_do_mes >= 0 ? 'D' : 'C')
				tipo_do_saldo_final = (saldo_final_do_mes >= 0 ? 'D' : 'C')
			end

			codigo_superavit_financeiro =
				if args[:codigo_superavit] == '1'
					'F'
				elsif args[:codigo_superavit] == '2'
					'P'
				else
					'N'
				end

			texto << '305'.sim_limite(3) + ',' #1
			texto << @configuracao.codigo_do_municipio_no_tcm.sim_limite(3) + "," #2
			texto << @orcamento[:exercicio].to_s.sim_limite_sem_aspas(4, "00") + "," #3
			texto << unidade_gestora[:codigo].to_s.rjust(2, '0') + ',' #4
			texto << args[:conta][:codigo].sim_preenche_a_direita(15) + ',' #5
			texto << codigo_superavit_financeiro.to_s.sim_limite(1) + ',' #6
			texto << (args[:fonte_de_recursos].nil? ? '0' : args[:fonte_de_recursos][0]).to_s.sim_limite(1) + ',' #7
			texto << (args[:fonte_de_recursos].nil? ? '000000000' : args[:fonte_de_recursos][1..9]).to_s.sim_limite(9) + ',' #8
			texto << (args[:fonte_de_recursos].nil? ? '0000' : args[:fonte_de_recursos][4..7]).to_s.sim_limite(4) + ',' #9
			texto << "#{data_inicial.year}#{data_inicial.month.to_s.rjust(2, '0')}" + ',' #10
			texto << (args[:conta][:subtitulo] == '2' ? 'S' : 'N').to_s.sim_limite(1) + ',' #11
			texto << (args[:conta][:subtitulo] == '2' ? unidade_gestora[:codigo].to_s.rjust(2, '0') : '0') + ',' # 12
			texto << (saldo_inicial_do_mes > 0 ? 'C' : 'D').sim_limite(1) + ',' #13
			texto << saldo_inicial_do_mes.to_s.sim_valor + ',' #14
			texto << args[:saldo_debito_total].to_s.sim_valor + ',' #15
			texto << args[:saldo_credito_total].to_s.sim_valor + ',' #16
			texto << tipo_do_saldo_final.sim_limite(1) + ',' #17
			texto << saldo_final_do_mes.abs.to_s.sim_valor + ',' #18
			texto << (args[:saldo_debito_total].to_d - args[:saldo_de_debito_contas_bancarias].to_d).to_s.sim_valor + ',' #19
			texto << args[:saldo_de_debito_contas_bancarias].to_s.sim_valor + ',' #20
			texto << (args[:saldo_credito_total].to_d - args[:saldo_de_creditos_contas_bancarias].to_d).to_s.sim_valor + ',' #21
			texto << args[:saldo_de_creditos_contas_bancarias].to_s.sim_valor #22

			return texto
		rescue => e
			if e.class.to_s == "NoMethodError"
				atributo_falho = e.message.split(" ")[2]
				coluna = CSV.parse(texto, :headers => false).last.count
				raise e.mensagem_traduzida(self, self.try(:codigo_movimentacao), atributo_falho, coluna)
			else
				raise e
			end
		end
	end
end