class Base::Pessoa < ApplicationRecord
	has_paper_trail
	include TradutorConcern

	attr_default :fornecedor, true
	attr_default :fundo_de_investimento, false
	attr_default :ativo, true
	attr_default :tipo_de_entidade, :nenhuma

	belongs_to :tipo_de_pessoa, class_name: 'Base::TipoDePessoa'
	belongs_to :estado_civil, class_name: 'Base::EstadoCivil'
	belongs_to :cidade, class_name: 'Base::Cidade'
	belongs_to :estado, class_name: 'Base::Estado', foreign_key: 'uf_orgao_expedidor_id'

	has_many :cnaes, class_name: 'Base::CnaeDaPessoa'
	has_many :responsaveis, class_name: 'Base::Responsavel', dependent: :destroy
	has_many :pessoas_contas_bancarias, dependent: :destroy, inverse_of: :pessoa
	# PessoaContaBancaria não tem mais vinculo com ContaBancaria
	#has_many :contas_bancarias, through: :pessoas_contas_bancarias, source: :conta_bancaria
	has_many :contas_extra_orcamentarias, class_name: 'Contabilidade::ContaExtraOrcamentaria'
	has_many :agentes_publicos_municipais, class_name: 'Base::AgentePublicoMunicipal'
	has_many :diarias, through: :agentes_publicos_municipais, class_name: 'Contabilidade::Diaria'
	has_many :empenhos, class_name: 'Contabilidade::Empenho'
	has_many :liquidacoes, through: :empenhos, class_name: 'Contabilidade::Liquidacao'
	has_many :pagamentos, through: :liquidacoes, class_name: 'Contabilidade::Pagamento'
	has_many :retencoes, through: :pagamentos, class_name: 'Contabilidade::Retencao'
	has_many :pessoas_dos_projetos, dependent: :restrict_with_exception, class_name: "Licitacao::PessoaDoProjeto", foreign_key: "pessoa_id"
	has_many :pessoas_do_pedido, dependent: :restrict_with_exception, class_name: 'Licitacao::PessoaDoPedido', foreign_key: "pessoa_id"
	has_many :projetos, through: :pessoas_dos_projetos, class_name: "Licitacao::Projeto"
	has_many :recebimento_de_materiais, class_name: 'GestaoDeEstoque::RecebimentoDeMaterial'
	has_many :requisicoes_de_materiais, class_name: 'Administrativo::RequisicaoDeMaterial'
	has_many :controle_de_pragas, class_name: 'GestaoDeEstoque::ControleDePraga', foreign_key: "empresa_responsavel_id"
	has_many :categorias_da_pessoa, class_name: 'Base::CategoriaDaPessoa'
	has_many :configuracoes_sim, class_name: '::ConfiguracaoSim'
	has_many :taloes_de_receita, class_name: 'Contabilidade::TalaoDeReceita'

	accepts_nested_attributes_for :cnaes, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :pessoas_contas_bancarias, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :categorias_da_pessoa, reject_if: :all_blank, allow_destroy: true

	validates_presence_of :tipo_de_pessoa_id, :nome, :data_do_cadastro, :cidade_id
	validates_presence_of :cpf, if: :pessoa_fisica?
	validates_presence_of :cnpj, if: :pessoa_juridica?
	validates_presence_of :porte, if: Proc.new{ pessoa_juridica? && !self.fundo_de_investimento? }
	validates_presence_of :email, if: Proc.new{ self.osc? }
	validates_presence_of :cep, if: Proc.new{ self.fornecedor == true }
	validates_presence_of :tipo_de_entidade, if: Proc.new{ entidade_publica? }

	validates_absence_of :porte, unless: :pessoa_juridica?

	validates_uniqueness_of :cpf, if: Proc.new{self.pessoa_fisica? && self.cpf_changed?}

	validates :pessoas_contas_bancarias, uniq_nested_attributes: { atributo: :conta_bancaria_id, mensagem: "Conta bancária deve ser única dentro do Fornecedor" }

	validates_numericality_of :dependentes, allow_nil: true

	validates_associated :pessoas_contas_bancarias

	validates_length_of :nome, maximum: 80
	validates_length_of :nome_fantasia, maximum: 80
	validates_length_of :cpf, maximum: 11
	validates_length_of :cnpj, maximum: 14
	validates_length_of :identidade, maximum: 25
	validates_length_of :inscricao_estadual, maximum: 25
	validates_length_of :orgao_expedidor, maximum: 10
	validates_length_of :inscricao_municipal, maximum: 15
	validates_length_of :cep, is: 8, allow_blank: true
	validates_length_of :logradouro, maximum: 120
	validates_length_of :numero, maximum: 8
	validates_length_of :complemento, maximum: 80
	validates_length_of :bairro, maximum: 60
	validates_length_of :telefone, maximum: 15
	validates_length_of :nit, maximum: 11
	validates_length_of :profissao, maximum: 60
	validates_length_of :naturalidade, maximum: 60
	validates_length_of :email, maximum: 120
	validates_length_of :email_alternativo, maximum: 120

	validates_cpf :cpf, if: :pessoa_fisica?
	validates_cnpj :cnpj, if: :pessoa_juridica?

	validates_format_of :email, :email_alternativo, :with => /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/, allow_blank: true

	validates :data_do_cadastro, date: true
	validates :data_da_emissao, date: { allow_blank: true }
	validates :data_de_nascimento, date: { allow_blank: true }
	validates :data_do_cadastro, sabado_ou_domingo_ou_feriado: { flexivel: false }
	validates :cnaes, uniq_nested_attributes: { atributo: :cnae_id, mensagem: "cnae deve ser único dentro de um fornecedor"}

	validate :verifica_cnae_principal
	validate :verifica_se_fornecedor_esta_em_uso, if: Proc.new {self.fornecedor_changed?}
	validate :verifica_se_tem_ao_menos_uma_cnae_principal
	validate :verifica_se_tem_gestor_do_SIM_vinculado, on: :update

	after_save :preenche_tipo_de_entidade_com_nenhuma, if: Proc.new{self.tipo_de_entidade.nil?}

	scope :fisicas, -> { joins(:tipo_de_pessoa).where('base_tipo_de_pessoas.codigo = ?', '1') }
	scope :juridicas, -> { joins(:tipo_de_pessoa).where('base_tipo_de_pessoas.codigo = ?', '2') }
	scope :fornecedores, -> { where(fornecedor: true) }
	scope :fundo_de_investimento, -> { where(fundo_de_investimento: true) }
	scope :diversos_contribuintes, -> { joins(:tipo_de_pessoa).where('base_tipo_de_pessoas.codigo = ?', '7') }

	enum porte: {
		mei: 0,
		microempresa: 1,
		pequeno_porte: 2,
		medio_porte: 3,
		grande_porte: 4,
		osc: 5,
		outros: 6
	}

	enum tipo_de_entidade: {
		federal: 1,
		estadual: 2,
		outro_municipio: 3,
		mesmo_municipio: 4,
		nenhuma: 5
	}

	def pagamentos_recebidos_por_competencia competencia, id_do_ultimo_pagamento
		return pagamentos.joins(:liquidacao).where('extract(month from contabilidade_liquidacoes.data_da_liquidacao) = ?', competencia).where.not(id: id_do_ultimo_pagamento).sum(:valor).to_f
	end

	def retencoes_de_irpf_por_competencia competencia, id_do_ultimo_pagamento
		return retencoes.joins(pagamento: :liquidacao).where('extract(month from contabilidade_liquidacoes.data_da_liquidacao) = ?', competencia).where.not(pagamento_id: id_do_ultimo_pagamento).sum(:valor_calculado).to_f
	end

	def retencoes_por_periodo data_inicial, data_final
		self.retencoes.joins(:pagamento).where('contabilidade_pagamentos.data BETWEEN ? AND ?', data_inicial, data_final).sum(&:valor_calculado)
	end

	def pessoa_fisica?
		self.tipo_de_pessoa.try(:codigo) == "1"
	end

	def pessoa_juridica?
		self.tipo_de_pessoa.try(:codigo) == "2"
	end

	def outros?
		self.tipo_de_pessoa.try(:codigo) == "3"
	end

	def folha_de_pagamento?
		self.tipo_de_pessoa.try(:codigo) == "6"
	end

	def diversos_contribuintes?
		self.tipo_de_pessoa.try(:codigo) == "7"
	end

	def me_ou_epp_ou_mei?
		microempresa? || pequeno_porte? || mei?
	end

	def cpf_ou_cnpj
		if folha_de_pagamento? && cnpj.nil?
			Configuracao.last.try(:cnpj_da_prefeitura)
		else
			cnpj.try(:as_cnpj) || cpf.try(:as_cpf)
		end
	end

	def cpf_ou_cnpj_sem_sinalizacao
		if folha_de_pagamento? && cnpj.nil?
			Configuracao.last.try(:cnpj_da_prefeitura)
		else
			cnpj || cpf
		end
	end

	def tipo_pessoa_to_sim
		if self.tipo_de_pessoa.codigo.to_s == '1'
			codigo = '2'
		elsif tipo_de_pessoa.codigo.to_s == '2'
			codigo = '1'
		else
			codigo = self.tipo_de_pessoa.codigo
		end
		return codigo.to_s
	end

	def texto_cpf_ou_cnpj
		if folha_de_pagamento?
			if cnpj.present?
				texto = 'CNPJ: ' + cnpj.try(:as_cnpj)
			else
				texto = 'CNPJ: ' +Configuracao.last.try(:cnpj_da_prefeitura)
			end
		elsif pessoa_fisica?
			texto = 'CPF: ' + cpf.try(:as_cpf_mascarado)
		elsif pessoa_juridica?
			texto = 'CNPJ: ' + cnpj.try(:as_cnpj)
		else
			texto = 'CPF/CNPJ: ' + cnpj.try(:as_cnpj) || cpf.try(:as_cpf_mascarado)
		end
	end

	def cpf_ou_cnpj_sem_pontos
		if folha_de_pagamento? & cnpj.nil?
			Configuracao.last.try(:cnpj_da_prefeitura).tr('./-', '')
		else
			cpf.present? ? cpf : cnpj
		end
	end

	def cpf_ou_cnpj_e_nome
		"#{cpf_ou_cnpj} - #{nome}"
	end

	def nome_e_cpf_ou_cnpj
		
		#"#{nome} (#{cpf_ou_cnpj})"
		array_de_retorno = ["#{nome}"]
		if cpf_ou_cnpj.present?
			array_de_retorno.push("(#{cpf_ou_cnpj})")
		end

		array_de_retorno.join(" ")
	end

	def tem_contas_bancarias?
		self.pessoas_contas_bancarias.count > 0
	end

	def endereco_completo
		if numero.present? && complemento.present? && bairro.present? && cep.present?
			"#{logradouro}, #{numero}, #{complemento}, #{bairro}, #{cidade.try(:nome)} - #{cidade.try(:estado).try(:nome)}, CEP: #{cep.try(:as_cep)}"
		elsif numero.present? && bairro.present? && cep.present?
			"#{logradouro}, #{numero}, #{bairro}, #{cidade.try(:nome)} - #{cidade.try(:estado).try(:nome)}, CEP: #{cep.try(:as_cep)}"
		elsif numero.present? && cep.present?
			"#{logradouro}, #{numero}, #{cidade.try(:nome)} - #{cidade.try(:estado).try(:nome)}, CEP: #{cep.try(:as_cep)}"
		else
			"#{logradouro}, #{cidade.try(:nome)} - #{cidade.try(:estado).try(:nome)}"
		end
	end

	def endereco_com_bairro
		if logradouro.present?
			if numero.present? && bairro.present?
				"#{logradouro}, #{numero} - #{bairro}"
			elsif numero.present?
				"#{logradouro}, #{numero}"
			else
				"#{logradouro} - #{bairro}"
			end
		end
	end

	def telefone_formatado
		telefone.try(:as_telefone)
	end

	def uf_endereco
		cidade.estado.uf
	end

	def cod_uf_endereco
		Base::Estado.codigo_ufs[cidade.estado.codigo_uf]
	end

	def estado_civil_sim
		if estado_civil.descricao == "Solteiro(a)"
			return 1
		elsif estado_civil.descricao == "Casado(a)"
			return 2
		elsif estado_civil.descricao == "Separado(a)"
			return 3
		elsif estado_civil.descricao == "Divorciado(a)"
			return 4
		elsif estado_civil.descricao == "Viúvo(a)"
			return 5
		end
	end

	def retorna_tipo_de_pessoa_formatada
		I18n.transliterate(self.tipo_de_pessoa.descricao.downcase.tr(" ","_")) if self.tipo_de_pessoa.present? && self.tipo_de_pessoa.descricao.present?
	end

	def define_ativo_inativo
		if self.ativo == true
			self.update(ativo: false)
		else
			self.update(ativo: true)
		end
	end

	def valor_arrecadado_no_periodo(data_inicial, data_final)
		self.taloes_de_receita.sum(&:valor)
	end

	private
	def verifica_se_tem_ao_menos_uma_cnae_principal
		errors.add(:cnaes, 'Deve ser selecionado um CNAE principal') unless cnaes.empty? || cnaes.any? {|cnae| cnae.principal }
	end

	def verifica_cnae_principal
		errors.add(:cnaes, 'Apenas um CNAE pode ser o principal da empresa') if cnaes.to_a.count {|cnae| cnae.principal } > 1
	end

	def verifica_se_fornecedor_esta_em_uso
		if (pessoas_do_pedido.any? || pessoas_dos_projetos.any?) && self.fornecedor == false
			errors.add(:fornecedor, "Não é possivel remover a função de fornecedor dessa pessoa, cadastro utilizado em processos licitatórios.")
		end
	end

	def verifica_se_tem_gestor_do_SIM_vinculado
		if self.configuracoes_sim.any? and self.configuracoes_sim.last.arquivo_id? and (self.nome_changed? || (self.pessoa_fisica? and self.cpf_changed?) || (self.pessoa_juridica? and self.cnpj_changed?))
			errors.add(:base, "Não é possivel editar essa pessoa, ela foi incluída como responsável no SIM.")
		end
	end

	def preenche_tipo_de_entidade_com_nenhuma
		self.update_column(:tipo_de_entidade, 5)
	end
end
