class GestaoDeEstoque::Transferencia < ApplicationRecord
  has_paper_trail

  include GeradorDeEventosContabeis
  include TradutorConcern
  include IncrementadorDeCodigoConcern
  include AASM
  include EstoqueConcern
  #gerador_de_eventos_contabeis codigo: 10, atributo_data: 'data_de_transferencia', atributo_codigo_movimentacao: 'codigo'

  belongs_to :unidade_orcamentaria, class_name: "Loa::UnidadeOrcamentaria"
	belongs_to :unidade_orcamentaria_de_destino, class_name: "Loa::UnidadeOrcamentaria", foreign_key: :unidade_orcamentaria_de_destino_id
	belongs_to :almoxarifado, class_name: "GestaoDeEstoque::Almoxarifado"
	belongs_to :almoxarifado_de_destino, class_name: "GestaoDeEstoque::Almoxarifado", foreign_key: :almoxarifado_de_destino_id
  belongs_to :orcamento, class_name: "Orcamento"

  has_many :recebimento_de_materiais, class_name: "GestaoDeEstoque::RecebimentoDeMaterial"
  has_many :requisicoes_de_materiais, class_name: "Administrativo::RequisicaoDeMaterial"
  has_many :movimentacoes_do_estoque, as: :origem, dependent: :destroy
  has_many :itens_da_transferencia, class_name: "GestaoDeEstoque::ItemDaTransferencia", dependent: :destroy
  has_many :programas_por_almoxarifado_e_transferencia, class_name: "GestaoDeEstoque::ProgramaPorAlmoxarifadoETransferencia", dependent: :destroy

  accepts_nested_attributes_for :itens_da_transferencia, allow_destroy: true
  accepts_nested_attributes_for :programas_por_almoxarifado_e_transferencia, allow_destroy: true, reject_if: :all_blank

	after_initialize :atribui_codigo_disponivel
  validates_presence_of :tipo_de_material , :almoxarifado_id , :almoxarifado_de_destino_id , :unidade_orcamentaria_id, :unidade_orcamentaria_de_destino_id, :data_de_transferencia

  validates_length_of :observacao, maximum: 600

  validate :data_de_transferencia_nao_pode_ser_de_orcamento_diferente
  validates  :data_de_transferencia, sabado_ou_domingo_ou_feriado: { flexivel: false }

  validate :data_nao_pode_ser_diferente_do_ano_corrente

  validate :valida_se_ja_houve_envio_do_sim

  after_save :preencher_itens

  enum status: {
    aberto: 0,
    solicitado: 1,
    recebido_parcialmente: 2,
    recebido: 3,
    confirmado: 4
	}

  enum tipo_de_material: {
    consumo: 0,
    permanente: 1,
    consumo_distribuicao_gratuita: 2
  }

  enum tipo_de_entrada: {
    definitivo: 0,
    provisorio: 1,
    remoto: 2
  }

  enum classificacao_tipo_de_material: {
    material_de_expediente: 0,
    material_de_consumo: 1,
    generos_alimenticios: 2,
    materiais_de_construcao: 3,
    autopecas: 4,
    medicamentos_e_materiais_hospitalares: 5,
    materiais_graficos: 6
  }

  aasm column: :status, enum: true, whiny_transitions: false do
    state :aberto, :initial => true
    state :solicitado
    state :recebido
    state :confirmado

    event :confirmar_recebimento_da_transferencia do
      transitions from: :confirmado, to: :recebido do
        guard do
          self.confirmado?
        end
        after do
          self.itens_da_transferencia.each do |item_da_transferencia|
            item_da_transferencia.adiciona_ou_atualiza_saldo_no_estoque
          end
        end
      end
    end

    event :solicitar_transferencia do
      transitions from: :aberto , to: :solicitado do
        guard do
          self.aberto?
        end
      end
    end

    event :confirmar_transferencia do
      transitions from: [:aberto, :solicitado] , to: :confirmado do
        guard do
          (self.aberto? || self.solicitado?)
        end
      end
    end
  end

  def data_de_transferencia_nao_pode_ser_de_orcamento_diferente
    if self.data_de_transferencia.present? && self.orcamento_id.present? && self.data_de_transferencia.year != self.orcamento.exercicio
      errors.add(:data_de_transferencia, "O exercício da transferência não pode ser diferente do exercício do orçamento")
    end
  end

  def atribui_codigo_disponivel
		if self.data_de_transferencia.present?
			gerar_codigo(self.data_de_transferencia, :codigo, :data_de_transferencia, :orcamento_id, self.orcamento_id)
		end
	end

  def existe_devolucao?
    GestaoDeEstoque::DevolucaoDeMaterial.where(origem: self.id).any?
  end

  def tipo_da_devolucao
    GestaoDeEstoque::DevolucaoDeMaterial.where(origem: self.id).last.tipo_de_devolucao rescue false
  end

  def quantidade_devolvida
    (self.itens_da_transferencia.sum(:quantidade).to_f - GestaoDeEstoque::DevolucaoDeMaterial.where(origem: self.id).last.itens_das_devolucoes_de_materiais.sum(:quantidade_devolvida).to_f) > 0
  end

  def preencher_itens
    if self.transferir_todos_os_itens && self.itens_da_transferencia.empty?
      estoques = GestaoDeEstoque::Estoque.where(almoxarifado_id: self.almoxarifado_id , unidade_orcamentaria_id: self.unidade_orcamentaria_id )
      estoques.each do |estoque|
        if estoque.quantidade_total_saldo > 0
          GestaoDeEstoque::ItemDaTransferencia.create!(
            transferencia_id: self.id ,
            quantidade: estoque.quantidade_total_saldo ,
            estoque_id: estoque.id,
            quantidade_disponivel: estoque.quantidade_total_saldo,
            item_id: estoque.item.id,
            valor_unitario: estoque.calcular_valor_medio_por_data_final(self.data_de_transferencia),
            total: estoque.calcular_valor_medio_por_data_final(self.data_de_transferencia) * estoque.quantidade_total_saldo
          )
        end
      end
    end
  end

  def data_nao_pode_ser_diferente_do_ano_corrente
    if data_de_transferencia.present? && data_de_transferencia.year.to_i != orcamento.exercicio.to_i
      errors.add(:data_de_transferencia, "Não pode ser diferente do ano/orçamento corrente.")
    end
  end
  
  def valida_se_ja_houve_envio_do_sim
    if existe_lote_do_sim?
			errors.add(:data_de_transferencia, 'O SIM do mês já foi enviado')
		elsif mes_bloqueado?
			errors.add(:data_de_transferencia, 'O mês do objeto está bloqueado, solicite o desbloqueio ao administrador')
    elsif estoque_do_mes_encerrado? (data_de_transferencia)
      errors.add(:data_de_transferencia, 'O mês está encerrado') 
		end
	end

	def existe_lote_do_sim?
		if data_de_transferencia.present?
			lote_sim = Tcm::Lote.find_by(
				orcamento_id: orcamento_id,
				tipo: [Tcm::Lote.tipos[:todos], Tcm::Lote.tipos[:contabilidade]],
				mes_de_referencia: data_de_transferencia.month,
				situacao: [Tcm::Lote.situacoes[:gerado], Tcm::Lote.situacoes[:finalizado]]
			)

			return lote_sim.present?
		end

		return false
	end 
end
