require 'active_support/concern'

module Tcm::BalanceteContaBancariaPcasp extend ActiveSupport::Concern
	# BB_____.BAL
	# ARQUIVO 306

	def todas_as_movimentacoes_de_conta_bancaria
		movimentacoes = Contabilidade::MovimentacaoDoPlanoDeContas.joins(unidade_orcamentaria: :tipo_de_unidade_administrativa).sem_encerramento
			.joins(:conta_bancaria)
			.where("base_contas_bancarias.conta_caixa_pcasp = false
				AND codigo_da_conta in ('111110100', '111110200', '111110602', '111110603', '111110604', '111111900')
				AND contabilidade_movimentacoes_do_plano_de_contas.conta_bancaria_id IS NOT NULL
				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_bancarias_pcasp
		self.carrega_dependencias_para_balancetes_conta_bancaria

		todas_as_movimentacoes_de_conta_bancaria = self.todas_as_movimentacoes_de_conta_bancaria

		movimentacoes_bancarias = todas_as_movimentacoes_de_conta_bancaria.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_de_conta_bancaria.group_by { |movimentacao|
			[
				movimentacao.codigo_da_conta,
				movimentacao.conta_bancaria_id,
				movimentacao.unidade_orcamentaria.unidade_gestora_id,
				movimentacao.codigo_completo_fr
			]
		}.each do |criterios, movimentacoes|
			codigo_da_conta = criterios[0]
			conta = @contas.select{ |i| i[:codigo] == codigo_da_conta}.first
			conta_bancaria_id = criterios[1]
			unidade_gestora_id = criterios[2]
			fonte_de_recursos = criterios[3]

			movimentacoes_dos_balancetes = @movimentacoes_das_contas_do_balancete.select { |i| 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_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, conta_bancaria_id, fonte_de_recursos).to_d

			args = {
				conta: conta,
				conta_bancaria_id: criterios[1],
				unidade_gestora_id: criterios[2],
				fonte_de_recursos: criterios[3],
				saldo_debito_total: saldo_debito_total,
				saldo_credito_total: saldo_credito_total,
				saldo_inicial_do_mes: saldo_inicial_do_mes
			}

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

		end
		self.update_column(:conteudo, conteudo)
	end

	def carrega_dependencias_para_balancetes_conta_bancaria
		@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 } }

		@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])
				.joins(movimentacao_do_plano_de_contas: :conta_bancaria)
				.where("base_contas_bancarias.conta_caixa_pcasp = false
					AND codigo_da_conta in ('111110100', '111110200', '111110602', '111110603', '111110604', '111111900')
					AND contabilidade_movimentacoes_do_plano_de_contas.conta_bancaria_id IS NOT NULL
					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_contas_bancarias(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
			conta_bancaria = @contas_bancarias.select{|i| i[:id] == args[:conta_bancaria_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

			numero_da_agencia = conta_bancaria[:numero_da_agencia].to_s.delete(".\/-").first(4)
			numero_da_agencia = numero_da_agencia.to_s.length < 6 ? numero_da_agencia.to_s.sim_preenche(6) : numero_da_agencia.to_s.sim_limite(6)

			texto << '306'.sim_limite(3) + ',' #1
			texto << @configuracao.codigo_do_municipio_no_tcm.sim_limite(3) + "," #2
			texto << @orcamento[:exercicio].to_s.sim_limite(4, "00") + "," #3
			texto << unidade_gestora[:codigo].to_s.rjust(2, '0') + ',' #4
			texto << args[:conta][:codigo].sim_preenche_a_direita(15) + ',' #5
			texto << conta_bancaria[:numero_do_banco].to_s.rjust(4, '0').sim_limite(4) + ',' #6
			texto << numero_da_agencia + ',' #7
			texto << conta_bancaria[:numero_da_conta].tr('.', '').tr('-', '').rjust(10, '0').sim_limite(10) + ',' #8

			# MANUAL TCE 2024 PAGINA 95
			texto << (args[:fonte_de_recursos].nil? ? '0' : args[:fonte_de_recursos][0]).to_s.sim_limite(1) + ',' #9
			texto << (args[:fonte_de_recursos].nil? ? '000000000' : args[:fonte_de_recursos][1..9]).to_s.sim_limite(9) + ',' #10
			texto << (args[:fonte_de_recursos].nil? ? '0000' : args[:fonte_de_recursos][4..7]).to_s.sim_limite(4) + ',' #11
			# MANUAL TCE 2024 PAGINA 95

			texto << "#{data_inicial.year}#{data_inicial.month.to_s.rjust(2, '0')}" + ',' #12
			texto << tipo_do_saldo_incial.sim_limite(1) + ',' #13
			texto << saldo_inicial_do_mes.to_f.abs.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

			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
