class Contabilidade::NotaFiscal < ApplicationRecord
	has_paper_trail

	include TradutorConcern
	include GeradorDeEventosContabeis

	attr_accessor :calcular_iss, :calcular_irpf, :calcular_irpj, :calcular_inss_pj, :calcular_inss_pf
	attr_accessor :isento_de_inss, :isento_de_irrf
	attr_accessor :logado_na_contabilidade
	attr_accessor :chave_de_acesso_parte1, :chave_de_acesso_parte2, :chave_de_acesso_parte3, :chave_de_acesso_parte4
	attr_accessor :skip_callback

	attr_default :skip_callback, false

	delegate :credor, to: :liquidacao

	belongs_to :liquidacao, class_name: 'Contabilidade::Liquidacao'
	belongs_to :cfop, class_name: 'Contabilidade::Cfop'
	belongs_to :arquivo, class_name: 'Tcm::Arquivo', required: false

	has_many :retencoes, class_name: 'Contabilidade::Retencao', dependent: :destroy

	has_one :linha, as: :modulo, class_name: "Tcm::Linha", dependent: :destroy

	accepts_nested_attributes_for :retencoes, reject_if: :all_blank, allow_destroy: true

	validates_presence_of :numero_da_nota, :tipo_de_emissao
	validates_presence_of :numeros_de_formularios, if: Proc.new { formulario? && (mercadoria? || mercadoria_avulsa?) }
	validates_presence_of :data_limite_de_expedicao, if: :formulario?
	validates_presence_of :data_de_emissao
	validates_presence_of :numero_dae, :serie_do_selo, :numero_do_selo, :numero_da_serie_do_selo, if: :informa_dae_e_selo?
	validates_presence_of :valor_de_desconto, if: :informa_desconto?
	validates_presence_of :numero_protocolo_de_autorizacao,:chave_de_acesso_parte2, :chave_de_acesso_parte4, if: Proc.new { informa_chave_de_acesso? && chave_de_acesso_parte1.present? }
	validates_presence_of :chave_de_verificacao, if: :informa_chave_de_verificacao?

	validates_absence_of :valor_de_desconto, unless: :informa_desconto?
	validates_absence_of :numero_protocolo_de_autorizacao, :chave_de_acesso_parte2, :chave_de_acesso_parte4 , unless: :informa_chave_de_acesso?
	validates_absence_of :chave_de_verificacao, unless: :informa_chave_de_verificacao?

	validates_associated :retencoes, if: :de_servico?

	validates :retencoes, uniq_nested_attributes: {
		atributo: :imposto_type, mensagem: "imposto deve ser único dentro da nota fiscal"
	}

	validates :data_de_emissao, date: { allow_blank: true }
	validates :data_limite_de_expedicao, date: { allow_blank: true }

	validate :data_de_emissao_menor_igual_a_da_liquidacao, unless: proc { aluguel? }
	validate :chave_de_acesso_valida?, if: Proc.new { self.eletronica_no_padrao_nacional? && (self.liquidacao.mercadoria? || self.liquidacao.mercadoria_avulsa?)}
	validate :valida_data_de_emissao_com_contexto_logado

	after_save :atualiza_campos_da_liquidacao, unless: proc { self.aluguel? }
	after_save :preenche_campo_chave_de_acesso, if: Proc.new { informa_chave_de_acesso? && chave_de_acesso_parte1.present? }
	after_save :gera_linha_para_arquivo_do_sim, if: Proc.new { self.tipo_de_emissao.present? && Configuracao.last.faz_envio_do_sim? && self.liquidacao.orcamento.exercicio > Date.today.year - 1}

	before_save :lanca_as_mudancas_no_restos_a_pagar_se_tiver, if: Proc.new { self.liquidacao.empenho.empenho_de_restos_a_pagar.present? }
	
	before_save :lanca_as_mudancas_do_restos_a_pagar_no_original, if: Proc.new { self.liquidacao.restos_a_pagar? && self.liquidacao.empenho.empenho_origem.present? && self.skip_callback == false}

	enum tipo_da_nota: {
		servico: 1, # 'S'
		mercadoria: 2, # 'M'
		mercadoria_avulsa: 3, # 'A'
		mercadoria_produtor: 4, # 'P'
		mercadoria_e_servico: 5, # 'X'
		servico_avulsa: 6, # 'V'
		aluguel: 7
	}

	enum tipo_de_emissao: {
		eletronica_no_padrao_nacional: 1,
		formulario: 2,
		eletronica_fora_do_padrao_nacional: 3,
		eletronica_sefaz: 4,
		eletronica_consumidor: 5
	}

	enum tipo_de_desconto: {
		sem_desconto: 1,
		global: 2,
		por_item: 3
	}

	# BOOLEANS
	def de_servico?
		servico? || mercadoria_e_servico? || servico_avulsa?
	end

	def de_mercadoria?
		mercadoria? || mercadoria_avulsa? || mercadoria_produtor? || mercadoria_e_servico?
	end

	def informa_dae_e_selo?
		formulario? && (mercadoria? || mercadoria_avulsa?)
	end

	def informa_desconto?
		global? || por_item?
	end

	def enviado_ao_sim?
		self.mes_bloqueado? || (arquivo_id.present? && arquivo_id > 0 && arquivo.lote.lote_processado_ou_enviado?)
	end

	def informa_chave_de_acesso?
		eletronica_no_padrao_nacional? || eletronica_consumidor?
	end

	def informa_chave_de_verificacao?
		eletronica_fora_do_padrao_nacional?
	end

	def tem_retencoes_extraorcamentarias?
		extraorcamentario_iss? || extraorcamentario_inss_pj? || extraorcamentario_irpj? || extraorcamentario_inss_pf? || extraorcamentario_irpf?
	end

	def cadastrar_retencoes?
		servico? || mercadoria_e_servico? || servico_avulsa?
	end

	# VALORES
	def valor_das_retencoes
		retencoes.sum(&:valor_calculado).to_f.round(2)
	end

	def valor_liquido
		(liquidacao.valor.to_f - valor_das_retencoes).to_f.round(2)
	end

	def data_antes_do_empenho?
		if data_de_emissao.present? && liquidacao.empenho.data_do_empenho.present?
			data_de_emissao < liquidacao.empenho.data_do_empenho
		end
	end

	def preenche_campo_chave_de_acesso
		if !liquidacao.nota_fiscal_a_preencher? && self.try(:chave_de_acesso_parte2) != ''
			chave_de_acesso = self.try(:chave_de_acesso_parte1)  + self.try(:chave_de_acesso_parte2)  + self.try(:chave_de_acesso_parte3) + self.try(:chave_de_acesso_parte4)
		else
			chave_de_acesso = ''
		end
		self.update_column(:chave_de_acesso, chave_de_acesso)
	end

	def chave_de_acesso_formatada
		tamanho_da_chave_com_todos_os_dados = 44
		if chave_de_acesso.to_s.strip.length == tamanho_da_chave_com_todos_os_dados
			"#{chave_de_acesso[0,2]}.#{chave_de_acesso[2,4]}.#{chave_de_acesso[6,2]}.#{chave_de_acesso[8,3]}.#{chave_de_acesso[11,3]}/#{chave_de_acesso[14,4]}-#{chave_de_acesso[18,2]}.#{chave_de_acesso[20,2]}.#{chave_de_acesso[22,3]}.#{chave_de_acesso[25,9]}.#{chave_de_acesso[34,1]}.#{chave_de_acesso[35,8]}.#{chave_de_acesso[43,1]}"
		else
			"#{chave_de_acesso}"
		end
	end

	#Validações

	def valida_data_de_emissao_com_contexto_logado
		errors.add(:data_de_emissao, "data selecionada está fora do exercício") if self.data_de_emissao.present? && contexto_atual.present? && self.data_de_emissao.year.to_i != contexto_atual.exercicio.to_i
	end

	def chave_de_acesso_valida?
		unless validar_chave_de_acesso
			errors.add(:chave_de_acesso, "Chave de acesso inválida")
			errors.add(:chave_de_acesso_parte1, "Chave de acesso inválida")
			errors.add(:chave_de_acesso_parte2, "Chave de acesso inválida")
			errors.add(:chave_de_acesso_parte3, "Chave de acesso inválida")
			errors.add(:chave_de_acesso_parte4, "Chave de acesso inválida")
		end
  end

	def validar_chave_de_acesso
		preenche_campo_chave_de_acesso rescue nil
		if !chave_de_acesso.nil?
			return false unless chave_de_acesso.length == 44
			passo = [2, 3, 4, 5, 6, 7, 8, 9]
			digitos = chave_de_acesso.chars.map(&:to_i)
			calculo_digito = digitos[0..-2].reverse
		
			total = 0
			calculo_digito.each_with_index do |digito, index|
				multiplicacao = digito * passo[index % passo.length]
				total += multiplicacao
			end
		
			resto = total % 11
			dv_calculado = 11 - resto
			if dv_calculado >= 10
				dv_calculado = 0
			end
			return digitos[43] == dv_calculado
		end
	end
	
	def data_de_emissao_menor_igual_a_da_liquidacao
		if liquidacao.present? && data_de_emissao.present?
			if liquidacao.data_da_liquidacao.present?
				errors.add(:data_de_emissao, "não pode ser posterior a data da liquidação #{liquidacao.data_da_liquidacao}") if data_de_emissao > liquidacao.data_da_liquidacao
			else
				errors.add(:data_de_emissao, "não pode ser posterior a data da liquidação #{liquidacao.data_de_solicitacao}") if data_de_emissao > liquidacao.data_de_solicitacao
			end
		end
	end

	def valida_inscricao_estadual
		if mercadoria? || mercadoria_produtor? || mercadoria_e_servico?
			raise "É necessário cadastrar inscrição estadual do fornecedor (id: #{self.credor.id} - CNPJ: #{self.credor.cnpj} - Nome: #{self.credor.nome})" if self.credor.inscricao_estadual.blank?
		end
	end

	def valida_inscricao_municipal
		raise "É necessário cadastrar inscrição municipal do fornecedor (id: #{self.credor.id} - CNPJ: #{self.credor.cnpj} - Nome: #{self.credor.nome})" if servico? && self.credor.inscricao_municipal.blank?
	end

	def tipo_da_nota_to_sim
		if servico?
			return'S'
		elsif mercadoria?
			return 'M'
		elsif mercadoria_avulsa?
			return 'A'
		elsif mercadoria_produtor?
			return'P'
		elsif mercadoria_e_servico?
			return 'X'
		elsif servico_avulsa?
			return 'V'
		end
	end

	def lanca_as_mudancas_no_restos_a_pagar_se_tiver
		campos_alterados = self.changed - ['liquidacao_id']

		if campos_alterados.size > 0
			nota_da_liquidacao_de_rp = self.liquidacao.empenho.empenho_de_restos_a_pagar.liquidacoes.where(numero: self.liquidacao.numero).try(:last).try(:nota_fiscal)

			if nota_da_liquidacao_de_rp.present?
				campos_alterados.each do |campo|
					nota_da_liquidacao_de_rp.update_column(campo, self["#{campo}".to_sym])
				end
			end
		end
	end

	def lanca_as_mudancas_do_restos_a_pagar_no_original
		campos_alterados = self.changed - ['liquidacao_id']

		if campos_alterados.size > 0
			liquidacao_origem = self.liquidacao.empenho.empenho_origem.liquidacoes.where(numero: self.liquidacao.numero).first rescue nil

			if liquidacao_origem.present?
				nota_da_liquidacao_origem = liquidacao_origem.try(:nota_fiscal) rescue nil

				if nota_da_liquidacao_origem.present?
					campos_alterados.each do |campo|
						nota_da_liquidacao_origem.update_column(campo.to_s, self["#{campo}".to_sym])
					end
				end
			end
		end
	end

	private

	def atualiza_campos_da_liquidacao
		liquidacao.update_attribute(:nota_fiscal_tipo, tipo_da_nota) if liquidacao.nota_fiscal_tipo != tipo_da_nota
		liquidacao.update_attribute(:nota_fiscal_numero, numero_da_nota) if liquidacao.nota_fiscal_numero != numero_da_nota
	end
end
