require 'rails_helper'

RSpec.describe Administrativo::ItemDaRequisicaoDeMaterial, type: :model do
  it{ is_expected.to belong_to(:estoque).class_name("GestaoDeEstoque::Estoque") }
  it{ is_expected.to belong_to(:item).class_name("Base::Item") }
  it{ is_expected.to belong_to(:unidade_de_medida).class_name("UnidadeDeMedida") }
  it{ is_expected.to belong_to(:requisicao_de_material).class_name("Administrativo::RequisicaoDeMaterial") }

  it{ is_expected.to have_many(:demandas_programadas).class_name("Administrativo::DemandaProgramada").dependent(:destroy) }

  it { is_expected.to accept_nested_attributes_for(:demandas_programadas).allow_destroy(true) }


  [:descricao_codigo_na_prefeitura_e_unidade_destacada,
    :codigo_e_descricao, :codigo_e_descricao_do_item].each do |atributo|
        it { is_expected.to delegate_method(atributo).to(:item) }
    end

  context "Valida validate_numericality_of quantidade_atendida" do
    before{
            allow(subject).to receive(:quantidade_atendida).and_return(1)
            allow(subject).to receive(:quantidade_requisitada).and_return(2)
          }
      it { is_expected.to validate_numericality_of(:quantidade_atendida) }
  end

  context "Quantidade deve ser maior que zero" do
    before(:each) do
      @requisicao = FactoryBot.build(:administrativo_requisicao_de_material)
      @requisicao.avulsa = false
      @requisicao.save(validate: false)
    end

    it "Quando é maior que zero" do
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material, requisicao_de_material_id: @requisicao.id, quantidade_requisitada: 5)

      item.validate
      expect(item.errors[:quantidade_requisitada]).to be_empty
    end
    it "Quando é zero" do
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material, requisicao_de_material_id: @requisicao.id, quantidade_requisitada: 0)

      item.validate
      expect(item.errors[:quantidade_requisitada]).to include "A quantidade requisitada é obrigatória e não pode ser menor ou igual a zero"
    end
  end

  context "Cria movimentação do estoque" do
    before(:each) do
      @requisicao = FactoryBot.build(:administrativo_requisicao_de_material, almoxarifado_id: 1, unidade_orcamentaria_id: 1, orcamento_id: 1)
      @requisicao.avulsa = true
      @requisicao.save(validate: false)
      @estoque = FactoryBot.build(:gestao_de_estoque_estoque, item_id: 1, almoxarifado_id: 1, unidade_orcamentaria_id: 1)
      @estoque.save(validate: false)
    end
    it "Quando tem estoque" do
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
        requisicao_de_material_id: @requisicao.id, quantidade_atendida: 5,
          estoque_id: @estoque.id)
          item.save(validate: false)
          item.adiciona_movimentacao_no_estoque
          expect(GestaoDeEstoque::MovimentacaoDoEstoque.last.valor_total).to eq item.valor_total
    end
    it "Quando não tem estoque" do
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
        requisicao_de_material_id: @requisicao.id, quantidade_atendida: 5)
          item.save(validate: false)
          expect(item.adiciona_movimentacao_no_estoque).to be_falsey
    end
  end

  context "Preenche Item id" do
    it "Quando tem Estoque" do
      estoque = FactoryBot.build(:gestao_de_estoque_estoque, item_id: 1, unidade_de_medida_id: 1)
      estoque.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material, estoque_id: estoque.id)
      item.save(validate: false)
      expect(item.item_id).to eq 1
      expect(item.unidade_de_medida_id).to eq 1
    end
  end

  context "Atualiza saldo no estoque" do
    it "Quando tem estoque" do
      requisicao = FactoryBot.build(:administrativo_requisicao_de_material, almoxarifado_id: 1, unidade_orcamentaria_id: 1, orcamento_id: 1)
      requisicao.avulsa = true
      requisicao.save(validate: false)
      estoque = FactoryBot.build(:gestao_de_estoque_estoque, item_id: 1, unidade_de_medida_id: 1, saldo_da_ordem_de_compra: 1)
      estoque.save(validate: false)
      movimentacao_entrada = FactoryBot.build(:gestao_de_estoque_movimentacao_do_estoque,
            valor_total: 10, quantidade_entrada: 10, estoque_id: estoque.id)
      movimentacao_entrada.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
        estoque_id: estoque.id, quantidade_atendida: 1, requisicao_de_material_id: requisicao.id)
      item.save(validate: false)
      item.adiciona_ou_atualiza_saldo_no_estoque
      estoque.reload
      expect(estoque.saldo_da_ordem_de_compra).to eq 9
    end
  end

  context "Possui conversão de medida" do
    before(:each) do
      @recebimento = FactoryBot.build(:gestao_de_estoque_recebimento_de_material)
      @recebimento.save(validate: false)
      @requisicao = FactoryBot.build(:administrativo_requisicao_de_material,
        almoxarifado_id: 1, unidade_orcamentaria_id: 1, orcamento_id: 1,
        recebimento_de_material_id: @recebimento.id)
      @requisicao.save(validate: false)
    end
    it "Quando Possui" do
      item_do_recebimento = FactoryBot.build(:gestao_de_estoque_itens_do_recebimento_de_material,
        recebimento_de_material_id: @recebimento.id, unidade_de_medida_de_conversao_id: 1)
      item_do_recebimento.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
          quantidade_atendida: 1, requisicao_de_material_id: @requisicao.id,
          item_id: item_do_recebimento.item_id )
      item.save(validate: false)
      expect(item.possui_conversao_de_unidade_de_medida?).to be_truthy
    end
    it "Quado não Possui" do
      item_do_recebimento = FactoryBot.build(:gestao_de_estoque_itens_do_recebimento_de_material,
        recebimento_de_material_id: @recebimento.id)
      item_do_recebimento.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
          quantidade_atendida: 1, requisicao_de_material_id: @requisicao.id,
          item_id: item_do_recebimento.item_id )
      item.save(validate: false)
      expect(item.possui_conversao_de_unidade_de_medida?).to be_falsey
    end
  end

  context "Quantidade disponivel da Ordem de Compra" do
    it "Quando tem Ordem de Compra" do
      ordem_de_compra = FactoryBot.build(:licitacao_ordem_de_compra)
      ordem_de_compra.save(validate: false)
      item_da_ordem = FactoryBot.build(:licitacao_item_da_ordem_de_compra, ordem_de_compra_id: ordem_de_compra.id)
      item_da_ordem.save(validate: false)
      recebimento = FactoryBot.build(:gestao_de_estoque_recebimento_de_material,ordem_de_compra_id: ordem_de_compra.id)
      recebimento.save(validate: false)
      requisicao = FactoryBot.build(:administrativo_requisicao_de_material,
        almoxarifado_id: 1, unidade_orcamentaria_id: 1, orcamento_id: 1,
        recebimento_de_material_id: recebimento.id)
      requisicao.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
            quantidade_atendida: 1, requisicao_de_material_id: requisicao.id,
            item_id: item_da_ordem.item_id)
      expect(item.quantidade_total_disponivel_da_ordem_de_compra).to eq 9.0
    end
    it "Quando não tem Ordem de Compra" do
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material, quantidade_atendida: 1)
      expect(item.quantidade_total_disponivel_da_ordem_de_compra).to eq 0
    end
  end

  context "Retorna Unidade de Medida do Recebimento" do
    it "Quando tem Unidade de Medida" do
      recebimento = FactoryBot.build(:gestao_de_estoque_recebimento_de_material)
      recebimento.save(validate: false)
      requisicao = FactoryBot.build(:administrativo_requisicao_de_material,
        almoxarifado_id: 1, unidade_orcamentaria_id: 1, orcamento_id: 1,
        recebimento_de_material_id: recebimento.id)
      requisicao.save(validate: false)
      unidade_de_medida = FactoryBot.build(:unidade_de_medida)
      unidade_de_medida.save(validate: false)
      item_do_recebimento = FactoryBot.build(:gestao_de_estoque_itens_do_recebimento_de_material,
        recebimento_de_material_id: recebimento.id, unidade_de_medida_de_conversao_id: unidade_de_medida.id, item_id: 1)
      item_do_recebimento.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
          quantidade_atendida: 1, requisicao_de_material_id: requisicao.id,
           item_id: 1 )
      item.save(validate: false)
      expect(item.unidade_de_medida_do_recebimento_de_material.id).to eq unidade_de_medida.id
    end
  end

  context "Saldo atual do estoque" do
    it "Quando tem estoque" do
      requisicao = FactoryBot.build(:administrativo_requisicao_de_material, almoxarifado_id: 1, unidade_orcamentaria_id: 1, orcamento_id: 1)
      requisicao.avulsa = true
      requisicao.save(validate: false)
      estoque = FactoryBot.build(:gestao_de_estoque_estoque, item_id: 1, unidade_de_medida_id: 1, saldo_da_ordem_de_compra: 1)
      estoque.save(validate: false)
      movimentacao_entrada = FactoryBot.build(:gestao_de_estoque_movimentacao_do_estoque,
            valor_total: 10, quantidade_entrada: 10, estoque_id: estoque.id)
      movimentacao_entrada.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
        estoque_id: estoque.id, quantidade_atendida: 1, requisicao_de_material_id: requisicao.id)
      expect(item.saldo_atual_do_recebimento_de_material).to eq 10
    end
  end

  context "Saldo atual da Ordem de Compra" do
    it "Quando Saldo é maior que 0" do
      requisicao = FactoryBot.build(:administrativo_requisicao_de_material, almoxarifado_id: 1, unidade_orcamentaria_id: 1, orcamento_id: 1)
      requisicao.avulsa = true
      requisicao.save(validate: false)
      estoque = FactoryBot.build(:gestao_de_estoque_estoque, item_id: 1, unidade_de_medida_id: 1, saldo_da_ordem_de_compra: 5)
      estoque.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
        estoque_id: estoque.id, quantidade_atendida: 1, requisicao_de_material_id: requisicao.id)
      expect(item.saldo_atual_da_ordem_de_compra).to eq 5
    end
    it "Quando saldo é menor ou igual a 0" do
      recebimento = FactoryBot.build(:gestao_de_estoque_recebimento_de_material)
      recebimento.save(validate: false)
      item_da_ordem = FactoryBot.build(:licitacao_item_da_ordem_de_compra,
        ordem_de_compra_id: recebimento.ordem_de_compra_id, quantidade: 9, item_id: 1)
        item_da_ordem.save(validate: false)
      requisicao = FactoryBot.build(:administrativo_requisicao_de_material,
          almoxarifado_id: 1, unidade_orcamentaria_id: 1,
          orcamento_id: 1, recebimento_de_material_id: recebimento.id)
      requisicao.save(validate: false)
      estoque = FactoryBot.build(:gestao_de_estoque_estoque, item_id: 1, unidade_de_medida_id: 1, saldo_da_ordem_de_compra: 0)
      estoque.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
        estoque_id: estoque.id, quantidade_atendida: 1, requisicao_de_material_id: requisicao.id, item_id: item_da_ordem.item_id )
      expect(item.saldo_atual_da_ordem_de_compra).to eq 9.0
    end
  end

  context "Saldo atual do estoque" do
    it "retorna nova saldo do estoque" do
      estoque = FactoryBot.build(:gestao_de_estoque_estoque, item_id: 1, unidade_de_medida_id: 1, saldo_da_ordem_de_compra: 0)
      estoque.save(validate: false)
      movimentacao_entrada = FactoryBot.build(:gestao_de_estoque_movimentacao_do_estoque,
            valor_total: 10, quantidade_entrada: 10, estoque_id: estoque.id)
      movimentacao_entrada.save(validate: false)
      item = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
        estoque_id: estoque.id, quantidade_atendida: 1, item_id:1 )
        estoque.reload
        expect(item.saldo_do_estoque).to eq 9
    end
  end

  describe "#quantidade_mais_proxima_a_vencer" do
    context "Quando estoque tem sub estoque" do
      it "retorna a quantidade do menor sub estoque" do
        estoque = FactoryBot.create(:gestao_de_estoque_estoque, :estoque_com_sub_estoque)
        estoque.sub_estoques_por_validade.last.update_attribute(:validade, Date.today)
        estoque.sub_estoques_por_validade.last.update_attribute(:quantidade, 5)
        FactoryBot.create(:gestao_de_estoque_sub_estoque_por_validade, estoque_id: estoque.id, validade: Date.today - 1.day, quantidade: 10 )
        estoque.reload

        item = FactoryBot.build(:administrativo_item_da_requisicao_de_material, estoque_id: estoque.id)
        expect(item.quantidade_mais_proxima_a_vencer).to eq 10
      end
    end
    context "Quando estoque não tem sub estoque" do
      it "retorna 0" do
        item = FactoryBot.build(:administrativo_item_da_requisicao_de_material, estoque_id: nil)
        expect(item.quantidade_mais_proxima_a_vencer).to eq 0
      end
    end
  end

  describe "#desconta_saldo_do_sub_estoque" do
    context "Quando estoque tem sub estoque" do
      it "atualiza a quantidade do mais proximo a vencer" do
        estoque = FactoryBot.create(:gestao_de_estoque_estoque, :estoque_com_sub_estoque)
        estoque.sub_estoques_por_validade.last.update_attribute(:validade, Date.today)
        estoque.sub_estoques_por_validade.last.update_attribute(:quantidade, 5)
        sub_estoque_mais_proximo_a_vencer = FactoryBot.create(:gestao_de_estoque_sub_estoque_por_validade, estoque_id: estoque.id, validade: Date.today - 1.day, quantidade: 10 )
        estoque.reload

        item = FactoryBot.build(:administrativo_item_da_requisicao_de_material, estoque_id: estoque.id, quantidade_atendida: 3)
        item.desconta_saldo_do_sub_estoque
        expect(sub_estoque_mais_proximo_a_vencer.reload.quantidade).to eq 7
      end
    end
    context "Quando estoque não tem sub estoque" do
      it "retorna false" do
        item = FactoryBot.build(:administrativo_item_da_requisicao_de_material, quantidade_atendida: 3)

        expect(item.desconta_saldo_do_sub_estoque).to be_falsey
      end
    end
  end
end
