require 'rails_helper'

RSpec.describe Administrativo::RequisicaoDeMaterial, type: :model do
  it { is_expected.to belong_to(:transferencia).class_name("GestaoDeEstoque::Transferencia") }
  it { is_expected.to belong_to(:orcamento).class_name("Orcamento") }
  it { is_expected.to belong_to(:recebimento_de_material).class_name("GestaoDeEstoque::RecebimentoDeMaterial") }
  it { is_expected.to belong_to(:unidade_orcamentaria).class_name("Loa::UnidadeOrcamentaria") }
  it { is_expected.to belong_to(:almoxarifado).class_name("GestaoDeEstoque::Almoxarifado") }
  it { is_expected.to belong_to(:fornecedor).class_name("Base::Pessoa").with_foreign_key(:fornecedor_id) }
  it { is_expected.to belong_to(:beneficiado).class_name("Base::Pessoa").with_foreign_key(:beneficiado_id) }
  it { is_expected.to belong_to(:usuario).class_name("Usuario") }
  it { is_expected.to belong_to(:almoxarifado_destino).class_name("GestaoDeEstoque::Almoxarifado").with_foreign_key(:almoxarifado_destino_id) }
  it { is_expected.to belong_to(:agente_publico).class_name("Base::AgentePublicoMunicipal").with_foreign_key(:responsavel_id) }

  it { is_expected.to have_many(:itens_das_requisicoes_de_materiais).class_name("Administrativo::ItemDaRequisicaoDeMaterial").dependent(:destroy) }
  it { is_expected.to have_many(:itens).through(:itens_das_requisicoes_de_materiais) }
  it { is_expected.to have_many(:detalhamentos_da_requisicao_de_material).through(:itens_das_requisicoes_de_materiais) }

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

  [:numero_da_requisicao, :data_da_requisicao, :unidade_orcamentaria_id,
    :almoxarifado_id, :status, :orcamento_id].each do |campo|
      it { is_expected.to validate_presence_of(campo) }
  end

  context "Quando Solicitação é requisição" do
    before { allow(subject).to receive(:solicitacao_requisicao?).and_return(true) }
    [ :tipo_de_material].each do |atributo|
      it { is_expected.to validate_presence_of(atributo) }
    end
  end

  context "Quando é saida de material" do
    before { allow(subject).to receive(:saida_de_material?).and_return(true) }
    [:almoxarifado_destino_id, :unidade_orcamentaria_destino_id, :responsavel_id].each do |atributo|
      it { is_expected.to validate_presence_of(atributo) }
    end
  end

  context "Cria recebimento" do
    it "Quando tem informações suficientes para criar um recebimento" do
      requisicao = FactoryBot.build(:administrativo_requisicao_de_material,
      almoxarifado_destino_id: 1, tipo_de_material: 1, unidade_orcamentaria_destino_id: 1,
      orcamento_id: 1)
      expect(requisicao.cria_recebimento).to be_truthy
    end
    it "Quando não tem informações suficientes para criar um recebimento" do
      requisicao = FactoryBot.build(:administrativo_requisicao_de_material)
      expect(requisicao.cria_recebimento).to be_falsey
    end
  end

  context "Possui Itens" do
    before(:each) do
      @requisicao = FactoryBot.build(:administrativo_requisicao_de_material)
    end
    it "Quando não possui item" do
      expect(@requisicao.possui_itens?).to be_falsey
    end
    it "Quando possui item" do
      @requisicao.save(validate: false)
      item_da_requisicao = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
      requisicao_de_material_id: @requisicao.id)
      item_da_requisicao.save(validate: false)
      expect(@requisicao.possui_itens?).to be_truthy
    end
  end

  context "Requisição tem quantidade atendida" do
    before(:each) do
      @requisicao = FactoryBot.build(:administrativo_requisicao_de_material)
      @requisicao.save(validate: false)
      @item_da_requisicao = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
      requisicao_de_material_id: @requisicao.id)
    end
    it "Quando quantidade atendida maior que zero" do
      @item_da_requisicao.update_attribute(:quantidade_atendida, 1)
      expect(@requisicao.existe_item_atendido?).to be_truthy
    end
    it "Quando quantidade atendida igual zero" do
      @item_da_requisicao.update_attribute(:quantidade_atendida, 0)
      expect(@requisicao.existe_item_atendido?).to be_falsey
    end
  end

  context "Requisição foi atendimento parcial" do
    before(:each) do
      @requisicao = FactoryBot.build(:administrativo_requisicao_de_material)
      @requisicao.save(validate: false)
      @item_da_requisicao = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
      requisicao_de_material_id: @requisicao.id, quantidade_requisitada: 10)
      @item_da_requisicao.save(validate: false)
    end
    it "Quando nem todos os itens foram atendidos" do
      @item_da_requisicao.update_attribute(:quantidade_atendida, 5)
      expect(@requisicao.atendimento_parcial?).to be_truthy
    end
    it "Quando todos os itens forma atendidos" do
      @item_da_requisicao.update_attribute(:quantidade_atendida, 10)
      expect(@requisicao.atendimento_parcial?).to be_falsey
    end
  end

  context "Número e quantidade itens" do
    before(:each) do
      @requisicao = FactoryBot.build(:administrativo_requisicao_de_material)
      @requisicao.atribui_numero_disponivel
      @requisicao.save(validate: false)
    end
    it "Quando tem item" do
      item_da_requisicao = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
      requisicao_de_material_id: @requisicao.id)
      item_da_requisicao.save(validate: false)
      expect(@requisicao.numero_e_quantidade_itens).to eq "#{@requisicao.numero_da_requisicao} (1 Itens)"
    end
    it "Quando não tem item" do
      expect(@requisicao.numero_e_quantidade_itens).to eq "#{@requisicao.numero_da_requisicao} (0 Itens)"
    end
  end

  context "AASM" do
    before(:each) do
      @requisicao = FactoryBot.build(:administrativo_requisicao_de_material,
        orcamento_id: 1)
    end
    it "Reabrir a requisição" do
      @requisicao.update_attribute(:status, :fechado)
      expect(@requisicao).to transition_from(:fechado).to(:aberto).on_event(:reabrir_requisicao)
    end
    it "Fechar a Requisição Com Item" do
      @requisicao.update_attribute(:status, :aberto)
      item_da_requisicao = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
      requisicao_de_material_id: @requisicao.id)
      item_da_requisicao.save(validate: false)
      expect(@requisicao).to transition_from(:aberto).to(:fechado).on_event(:fechar_requisicao)
    end
    it "Enviar requisição ao almoxarifado" do
      @requisicao.update_attribute(:status, :fechado)
      expect(@requisicao).to transition_from(:fechado).to(:enviado_ao_almoxarifado).on_event(:enviar_ao_almoxarifado)
    end
    it "Receber no almoxarifado" do
      @requisicao.update_attribute(:status, :enviado_ao_almoxarifado)
      expect(@requisicao).to transition_from(:enviado_ao_almoxarifado).to(:recebido_pelo_almoxarifado).on_event(:receber_no_almoxarifado)
    end
    it "Recusar no almoxarifado" do
      @requisicao.update_attribute(:status, :enviado_ao_almoxarifado)
      expect(@requisicao).to transition_from(:enviado_ao_almoxarifado).to(:recusado).on_event(:recusar)
    end
    it "Em atendimento" do
      @requisicao.update_attribute(:status, :recebido_pelo_almoxarifado)
      expect(@requisicao).to transition_from(:recebido_pelo_almoxarifado).to(:em_atendimento).on_event(:atender_requisicao)
    end
    it "Concluir atendimento parcial" do
      estoque = FactoryBot.create(:gestao_de_estoque_estoque, item_id: 1,
      unidade_de_medida_id: 1,
      almoxarifado_id: 1,
      unidade_orcamentaria_id: 1)
      @requisicao.update_attribute(:status, :em_atendimento)
      item_da_requisicao = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
      requisicao_de_material_id: @requisicao.id, quantidade_atendida: 1,
      item_id: 1, unidade_de_medida_id: 1,estoque_id: estoque.id)
      item_da_requisicao.save(validate: false)
      expect(@requisicao).to transition_from(:em_atendimento).to(:atendido_parcialmente).on_event(:concluir_atendimento_parcial)
    end
    it "Concluir atendimento total" do
      estoque = FactoryBot.create(:gestao_de_estoque_estoque, item_id: 1,
      unidade_de_medida_id: 1,
      almoxarifado_id: 1,
      unidade_orcamentaria_id: 1)
      @requisicao.update_attribute(:status, :em_atendimento)
      item_da_requisicao = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
      requisicao_de_material_id: @requisicao.id, quantidade_atendida: 1,
      item_id: 1, unidade_de_medida_id: 1, estoque_id: estoque.id)
      item_da_requisicao.save(validate: false)
      expect(@requisicao).to transition_from(:em_atendimento).to(:atendido).on_event(:concluir_atendimento)
    end
    it "Concluir consumo" do
      estoque = FactoryBot.create(:gestao_de_estoque_estoque, item_id: 1,
      unidade_de_medida_id: 1,
      almoxarifado_id: 1,
      unidade_orcamentaria_id: 1)
      @requisicao.update_attribute(:tipo_de_solicitacao, :solicitacao_consumo)
      item_da_requisicao = FactoryBot.build(:administrativo_item_da_requisicao_de_material,
      requisicao_de_material_id: @requisicao.id, quantidade_atendida: 1,
      item_id: 1, unidade_de_medida_id: 1, estoque_id: estoque.id)
      item_da_requisicao.save(validate: false)
      expect(@requisicao).to transition_from(:aberto).to(:consumido).on_event(:concluir_consumo)
    end
  end

  context "Preenche os valores da requisição com ordem de compra" do
    before(:each) do
      @requisicao = FactoryBot.build(:administrativo_requisicao_de_material)
    end
    it "Quando tem ordem de compra" do
      recebimento = FactoryBot.build(:gestao_de_estoque_recebimento_de_material)
      recebimento.save(validate: false)
      expect(@requisicao.preenche_campos_requisicao_de_material(recebimento.ordem_de_compra_id)).to be_truthy
    end
    it "Quando não tem ordem de compra" do
      expect(@requisicao.preenche_campos_requisicao_de_material(nil)).to be_falsey
    end
  end

  describe "#atender_todos_os_itens" do
    context "Quando atende" do
      it "Item tem toda quantidade requisitada totalmente atendida" do
        requisicao = FactoryBot.create(:administrativo_requisicao_de_material, :com_itens)
        requisicao.reload

        requisicao.itens_das_requisicoes_de_materiais.last.update_columns(quantidade_requisitada: 5, quantidade_atendida: 2)
        requisicao.atender_todos_os_itens
        expect(requisicao.itens_das_requisicoes_de_materiais.last.reload.quantidade_atendida).to eq 5
      end
    end
  end

  describe "#detalhamento_precisa_existir" do
    context "Válido" do
      it "Quando não possui classificacao" do
        requisicao = FactoryBot.build(:administrativo_requisicao_de_material, classificacao: nil)
        requisicao.validate

        expect(requisicao.errors[:base_detalhamento]).to_not include("Precisa existir pelo menos um detalhamento")
      end
      it "Quando possui classificação mas possui detalhamento" do
        requisicao = FactoryBot.build(:administrativo_requisicao_de_material, classificacao: :doacao)
        requisicao.detalhamentos_da_requisicao_de_material.build()
        requisicao.validate

        expect(requisicao.errors[:base_detalhamento]).to_not include("Precisa existir pelo menos um detalhamento")
      end
    end
    context "Inválido" do
      it "Quand possui classificação sem detalhamento" do
        requisicao = FactoryBot.build(:administrativo_requisicao_de_material, classificacao: :doacao)
        requisicao.validate

        expect(requisicao.errors[:base_detalhamento]).to include("Precisa existir pelo menos um detalhamento")
      end
    end
  end
end
