# frozen_string_literal: true

require 'system_helper'

RSpec.describe "
  Managing a hub's inventory
  I want to override the stock level and price of products
  Without affecting other hubs that share the same products
", feature: :inventory do
  include AdminHelper
  include AuthenticationHelper
  include WebHelper

  context "as the manager of a hub" do
    let!(:hub) { create(:distributor_enterprise) }
    let!(:hub2) { create(:distributor_enterprise) }
    let!(:producer) { create(:supplier_enterprise) }
    let!(:producer_managed) { create(:supplier_enterprise) }
    let!(:producer_related) { create(:supplier_enterprise) }
    let!(:producer_unrelated) { create(:supplier_enterprise) }
    let!(:er1) {
      create(:enterprise_relationship, parent: producer, child: hub,
                                       permissions_list: [:create_variant_overrides])
    }
    let!(:er2) {
      create(:enterprise_relationship, parent: producer_related, child: hub,
                                       permissions_list: [:create_variant_overrides])
    }
    let(:user) { create(:user, enterprises: [hub, producer_managed]) }

    before { login_as user }

    describe "selecting a hub" do
      let!(:er1) {
        create(:enterprise_relationship, parent: hub2, child: producer_managed,
                                         permissions_list: [:add_to_order_cycle])
      } # This er should not confer ability to create VOs for hub2

      it "displays a list of hub choices (ie. only those managed by the user)" do
        visit spree.admin_dashboard_path
        click_link 'Products'
        click_link 'Inventory'

        # Selects the hub automatically when only one is available
        expect(page).to have_select2 'hub_id', options: [hub.name]
      end
    end

    context "when inventory_items exist for variants" do
      let!(:product) {
        create(:simple_product, supplier_id: producer.id, variant_unit: 'weight',
                                variant_unit_scale: 1)
      }
      let!(:variant) { create(:variant, product:, unit_value: 1, price: 1.23, on_hand: 12) }
      let!(:inventory_item) { create(:inventory_item, enterprise: hub, variant: ) }

      let!(:product_managed) {
        create(:simple_product, supplier_id: producer_managed.id, variant_unit: 'weight',
                                variant_unit_scale: 1)
      }
      let!(:variant_managed) {
        create(:variant, product: product_managed, supplier: producer_managed, unit_value: 3,
                         price: 3.65, on_hand: 2)
      }
      let!(:inventory_item_managed) {
        create(:inventory_item, enterprise: hub, variant: variant_managed )
      }

      let!(:product_related) { create(:simple_product, supplier_id: producer_related.id) }
      let!(:variant_related) {
        create(:variant, product: product_related, supplier: producer_related, unit_value: 2,
                         price: 2.34, on_hand: 23)
      }
      let!(:inventory_item_related) {
        create(:inventory_item, enterprise: hub, variant: variant_related )
      }

      let!(:product_unrelated) { create(:simple_product, supplier_id: producer_unrelated.id) }

      context "when a hub is selected" do
        before do
          visit '/admin/inventory'
          select2_select hub.name, from: 'hub_id'
        end

        context "with no overrides" do
          it "displays the list of products with variants" do
            expect(page).to have_table_row ['Producer', 'Product', 'Price', 'On Hand', 'On Demand?']
            expect(page).to have_table_row ['', product.name, '', '', '']
            within "tr#v_#{variant.id}" do |tr|
              expect(tr).to have_content(producer.name)
            end
            expect(page).to have_input "variant-overrides-#{variant.id}-price", placeholder: '1.23'
            expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand",
                                       placeholder: '12'

            expect(page).to have_table_row ['', product_related.name, '', '', '']
            within "tr#v_#{variant_related.id}" do |tr|
              expect(tr).to have_content(producer_related.name)
            end
            expect(page).to have_input "variant-overrides-#{variant_related.id}-price",
                                       placeholder: '2.34'
            expect(page).to have_input "variant-overrides-#{variant_related.id}-count_on_hand",
                                       placeholder: '23'

            # filters the products to those the hub can override
            expect(page).not_to have_content producer_managed.name
            expect(page).not_to have_content product_managed.name
            expect(page).not_to have_content producer_unrelated.name
            expect(page).not_to have_content product_unrelated.name

            # Filters based on the producer select filter
            expect(page).to have_selector "#v_#{variant.id}"
            expect(page).to have_selector "#v_#{variant_related.id}"
            select2_select producer.name, from: 'producer_filter'
            expect(page).to have_selector "#v_#{variant.id}"
            expect(page).not_to have_selector "#v_#{variant_related.id}"
            select2_select 'All', from: 'producer_filter'

            # Filters based on the quick search box
            expect(page).to have_selector "#v_#{variant.id}"
            expect(page).to have_selector "#v_#{variant_related.id}"
            fill_in 'query', with: product.name
            expect(page).to have_selector "#v_#{variant.id}"
            expect(page).not_to have_selector "#v_#{variant_related.id}"
            fill_in 'query', with: ''

            # Clears the filters
            expect(page).to have_selector "tr#v_#{variant.id}"
            expect(page).to have_selector "tr#v_#{variant_related.id}"
            select2_select producer.name, from: 'producer_filter'
            fill_in 'query', with: product_related.name
            expect(page).not_to have_selector "tr#v_#{variant.id}"
            expect(page).not_to have_selector "tr#v_#{variant_related.id}"
            click_button 'Clear All'
            expect(page).to have_selector "tr#v_#{variant.id}"
            expect(page).to have_selector "tr#v_#{variant_related.id}"

            # Show/Hide products
            toggle_columns "Hide"
            expect(page).to have_selector "tr#v_#{variant.id}"
            expect(page).to have_selector "tr#v_#{variant_related.id}"
            within "tr#v_#{variant.id}" do
              click_button 'Hide'
            end
            expect(page).not_to have_selector "tr#v_#{variant.id}"
            expect(page).to have_selector "tr#v_#{variant_related.id}"
            first("div#views-dropdown").click
            first("div#views-dropdown div.menu div.menu_item", text: "Hidden Products").click
            expect(page).to have_selector "tr#v_#{variant.id}"
            expect(page).not_to have_selector "tr#v_#{variant_related.id}"
            within "tr#v_#{variant.id}" do
              click_button 'Add'
            end
            expect(page).not_to have_selector "tr#v_#{variant.id}"
            expect(page).not_to have_selector "tr#v_#{variant_related.id}"
            first("div#views-dropdown").click
            first("div#views-dropdown div.menu div.menu_item", text: "Inventory Products").click
            expect(page).to have_selector "tr#v_#{variant.id}"
            expect(page).to have_selector "tr#v_#{variant_related.id}"
          end

          it "creates new overrides" do
            toggle_columns "SKU"

            fill_in "variant-overrides-#{variant.id}-sku", with: 'NEWSKU'
            fill_in "variant-overrides-#{variant.id}-price", with: '777.77'
            select_on_demand variant, :no
            fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '123'
            expect(page).to have_content "Changes to one override remain unsaved."

            expect do
              click_button 'Save Changes'
              expect(page).to have_content "Changes saved."
            end.to change { VariantOverride.count }.by(1)

            vo = VariantOverride.last
            expect(vo.variant_id).to eq(variant.id)
            expect(vo.hub_id).to eq(hub.id)
            expect(vo.sku).to eq("NEWSKU")
            expect(vo.price).to eq(777.77)
            expect(vo.on_demand).to eq(false)
            expect(vo.count_on_hand).to eq(123)
          end

          describe "creating and then updating the new override" do
            it "updates the same override instead of creating a duplicate" do
              # When I create a new override
              fill_in "variant-overrides-#{variant.id}-price", with: '777.77'
              select_on_demand variant, :no
              fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '123'
              expect(page).to have_content "Changes to one override remain unsaved."

              expect do
                click_button 'Save Changes'
                expect(page).to have_content "Changes saved."
              end.to change { VariantOverride.count }.by(1)

              # And I update its settings without reloading the page
              fill_in "variant-overrides-#{variant.id}-price", with: '111.11'
              fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '111'
              expect(page).to have_content "Changes to one override remain unsaved."

              # Then I shouldn't see a new override
              expect do
                click_button 'Save Changes'
                expect(page).to have_content "Changes saved."
              end.to change { VariantOverride.count }.by(0)

              # And the override should be updated
              vo = VariantOverride.last
              expect(vo.variant_id).to eq(variant.id)
              expect(vo.hub_id).to eq(hub.id)
              expect(vo.price).to eq(111.11)
              expect(vo.on_demand).to eq(false)
              expect(vo.count_on_hand).to eq(111)
            end
          end

          it "displays an error when unauthorised to access the page" do
            fill_in "variant-overrides-#{variant.id}-price", with: '777.77'
            fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '123'
            expect(page).to have_content "Changes to one override remain unsaved."

            # Set a user without suficient permissions
            allow_any_instance_of(Spree::Admin::BaseController).to receive(:current_spree_user)
              .and_return(build(:user))

            expect do
              click_button 'Save Changes'

              # We need to wait_until because the save action is not fast enough
              # for the have_content matcher
              wait_until { page.find("#status-message").text != "Saving..." }
              expect(page).to have_content "I couldn't get authorisation to save those changes, " \
                                           "so they remain unsaved."
            end.to change { VariantOverride.count }.by(0)
          end

          it "displays an error when unauthorised to update a particular override" do
            fill_in "variant-overrides-#{variant_related.id}-price", with: '777.77'
            fill_in "variant-overrides-#{variant_related.id}-count_on_hand", with: '123'
            expect(page).to have_content "Changes to one override remain unsaved."

            er2.destroy

            expect do
              click_button 'Save Changes'
              expect(page).to have_content "I couldn't get authorisation to save those changes, " \
                                           "so they remain unsaved."
            end.to change { VariantOverride.count }.by(0)
          end
        end

        context "with overrides" do
          let!(:vo) {
            create(
              :variant_override,
              on_demand: true, count_on_hand: -5,
              variant:, hub:, price: 77.77, default_stock: 1000, resettable: true,
              tag_list: ["tag1", "tag2", "tag3"]
            )
          }
          let!(:vo_no_auth) {
            create(:variant_override, variant:, hub: hub2, price: 1, count_on_hand: 2)
          }
          let!(:product2) {
            create(:simple_product, supplier_id: producer.id, variant_unit: 'weight',
                                    variant_unit_scale: 1)
          }
          let!(:variant2) {
            create(:variant, product: product2, unit_value: 8, price: 1.00, on_hand: 12)
          }
          let!(:inventory_item2) { create(:inventory_item, enterprise: hub, variant: variant2) }
          let!(:vo_no_reset) {
            create(:variant_override, variant: variant2, hub:, price: 3.99, count_on_hand: 40,
                                      default_stock: 100, resettable: false)
          }
          let!(:variant3) {
            create(:variant, product:, unit_value: 2, price: 5.00, on_hand: 6)
          }
          let!(:vo3) {
            create(:variant_override, variant: variant3, hub:, price: 6, count_on_hand: 7,
                                      sku: "SOMESKU", default_stock: 100, resettable: false)
          }
          let!(:inventory_item3) { create(:inventory_item, enterprise: hub, variant: variant3) }

          before do
            visit '/admin/inventory'
            select2_select hub.name, from: 'hub_id'
          end

          it "product values are affected by overrides" do
            expect(page).to have_input "variant-overrides-#{variant.id}-price",
                                       with: '77.77', placeholder: '1.23'
            expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand",
                                       with: "", placeholder: 'On demand'
            expect(page).to have_select "variant-overrides-#{variant.id}-on_demand",
                                        selected: 'Yes'

            expect(page).to have_input "variant-overrides-#{variant2.id}-count_on_hand",
                                       with: "40", placeholder: ""
          end

          it "updates existing overrides" do
            fill_in "variant-overrides-#{variant.id}-price", with: '22.22'
            select_on_demand variant, :no
            fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '8888'
            expect(page).to have_content "Changes to one override remain unsaved."

            expect do
              click_button 'Save Changes'
              expect(page).to have_content "Changes saved."
            end.to change { VariantOverride.count }.by(0)

            vo.reload
            expect(vo.variant_id).to eq(variant.id)
            expect(vo.hub_id).to eq(hub.id)
            expect(vo.price).to eq(22.22)
            expect(vo.on_demand).to eq(false)
            expect(vo.count_on_hand).to eq(8888)
          end

          it "updates on_demand settings" do
            select_on_demand variant, :no
            click_button 'Save Changes'
            expect(page).to have_content 'Changes saved.'

            vo.reload
            expect(vo.on_demand).to eq(false)

            select_on_demand variant, :yes
            click_button 'Save Changes'
            expect(page).to have_content 'Changes saved.'

            vo.reload
            expect(vo.on_demand).to eq(true)

            select_on_demand variant, :use_producer_settings
            click_button 'Save Changes'
            expect(page).to have_content 'Changes saved.'

            vo.reload
            expect(vo.on_demand).to be_nil
          end

          # Any new fields added to the VO model need to be added to this test
          it "deletes overrides when values are cleared" do
            toggle_columns "Enable Stock Reset?", "Tags"

            # Clearing values by 'inheriting'
            toggle_columns "Inherit?"
            check "variant-overrides-#{variant3.id}-inherit"
            # Hide the Inherit column again. When that column is visible, the
            # size of the Tags column is too short and tags can't be removed.
            # This is a bug and the next line can be removed once it is fixed:
            # https://github.com/openfoodfoundation/openfoodnetwork/issues/3310
            toggle_columns "Inherit?"

            # Clearing values manually
            fill_in "variant-overrides-#{variant.id}-price", with: ''
            select_on_demand variant, :use_producer_settings
            fill_in "variant-overrides-#{variant.id}-default_stock", with: ''
            within "tr#v_#{variant.id}" do
              vo.tag_list.each do |tag|
                within "li.tag-item", text: "#{tag} ✖" do
                  find("a.remove-button").click
                end
              end
            end
            page.uncheck "variant-overrides-#{variant.id}-resettable"
            expect(page).to have_content "Changes to 2 overrides remain unsaved."

            expect do
              click_button 'Save Changes'
              expect(page).to have_content "Changes saved."
            end.to change { VariantOverride.count }.by(-2)

            expect(VariantOverride.where(id: vo.id)).to be_empty
            expect(VariantOverride.where(id: vo3.id)).to be_empty
          end

          it "resets stock to defaults" do
            first("div#bulk-actions-dropdown").click
            first("div#bulk-actions-dropdown div.menu div.menu_item",
                  text: "Reset Stock Levels To Defaults").click
            expect(page).to have_content 'Stocks reset to defaults.'
            vo.reload
            expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand",
                                       with: "1000", placeholder: ""
            expect(vo.count_on_hand).to eq(1000)
          end

          it "doesn't reset stock levels if the behaviour is disabled" do
            first("div#bulk-actions-dropdown").click
            first("div#bulk-actions-dropdown div.menu div.menu_item",
                  text: "Reset Stock Levels To Defaults").click
            vo_no_reset.reload
            expect(page).to have_input "variant-overrides-#{variant2.id}-count_on_hand",
                                       with: "40", placeholder: ""
            expect(vo_no_reset.count_on_hand).to eq(40)
          end

          it "prompts to save changes before reset if any are pending" do
            fill_in "variant-overrides-#{variant.id}-price", with: '200'
            first("div#bulk-actions-dropdown").click
            first("div#bulk-actions-dropdown div.menu div.menu_item",
                  text: "Reset Stock Levels To Defaults").click
            expect(page).to have_content "Save changes first"
          end

          describe "ensuring that on demand and count on hand settings are compatible" do
            it "clears count on hand when not limited stock" do
              # It clears count_on_hand when selecting true on_demand.
              select_on_demand variant, :no
              fill_in "variant-overrides-#{variant.id}-count_on_hand", with: "200"
              select_on_demand variant, :yes
              expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand", with: ""

              # It clears count_on_hand when selecting nil on_demand.
              select_on_demand variant, :no
              fill_in "variant-overrides-#{variant.id}-count_on_hand", with: "200"
              select_on_demand variant, :use_producer_settings
              expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand", with: ""

              # It saves the changes.
              click_button 'Save Changes'
              expect(page).to have_content 'Changes saved.'
              vo.reload
              expect(vo.count_on_hand).to be_nil
              expect(vo.on_demand).to be_nil
            end

            it "provides explanation when attempting to save variant override with incompatible " \
               "stock settings" do
              # Successfully change stock settings.
              select_on_demand variant, :no
              fill_in "variant-overrides-#{variant.id}-count_on_hand", with: "1111"
              click_button 'Save Changes'
              expect(page).to have_content 'Changes saved.'

              # Make stock settings incompatible.
              select_on_demand variant, :no
              fill_in "variant-overrides-#{variant.id}-count_on_hand", with: ""

              # It does not save the changes.
              click_button 'Save Changes'
              expect(page).to have_content 'must be specified because forcing limited stock'
              expect(page).not_to have_content 'Changes saved.'

              vo.reload
              expect(vo.count_on_hand).to eq(1111)
              expect(vo.on_demand).to eq(false)
            end
          end
        end
      end
    end

    describe "when manually placing an order" do
      let!(:order_cycle) { create(:order_cycle_with_overrides, name: "Overidden") }
      let(:distributor) { order_cycle.distributors.first }
      let(:product) { order_cycle.products.first }

      before do
        login_as_admin
        visit spree.new_admin_order_path
        select2_select distributor.name, from: 'order_distributor_id'
        select2_select order_cycle.name, from: 'order_order_cycle_id'
        click_button 'Next'
        click_link "Order Details"
      end

      # Reproducing a bug, issue #1446
      it "shows the overridden price" do
        select2_select product.name, from: 'add_variant_id', search: true
        find('button.add_variant').click
        expect(page).to have_selector("table.index tbody tr") # Wait for JS
        expect(page).to have_content(product.variants.first.variant_overrides.first.price)
      end
    end

    describe "when inventory_items do not exist for variants" do
      let!(:product) {
        create(:simple_product, supplier_id: producer.id, variant_unit: 'weight',
                                variant_unit_scale: 1)
      }
      let!(:variant1) {
        create(:variant, product:, unit_value: 1, price: 1.23, on_hand: 12)
      }
      let!(:variant2) { create(:variant, product:, unit_value: 2, price: 4.56, on_hand: 3) }

      context "when a hub is selected" do
        before do
          visit '/admin/inventory'
          select2_select hub.name, from: 'hub_id'
        end

        it "alerts the user to the presence of new products, and allows them to be added " \
           "or hidden" do
          expect(page).not_to have_selector "table#variant-overrides tr#v_#{variant1.id}"
          expect(page).not_to have_selector "table#variant-overrides tr#v_#{variant2.id}"

          expect(page).to have_selector '.alert-row span.message',
                                        text: "There are 1 new products available to add to your " \
                                              "inventory."
          click_button "Review Now"

          expect(page).to have_table_row ['Producer', 'Product', 'Variant', 'Add', 'Hide']
          expect(page).to have_selector "table#new-products tr#v_#{variant1.id}"
          expect(page).to have_selector "table#new-products tr#v_#{variant2.id}"
          within "table#new-products tr#v_#{variant1.id}" do
            click_button 'Add'
          end
          within "table#new-products tr#v_#{variant2.id}" do
            click_button 'Hide'
          end
          expect(page).not_to have_selector "table#new-products tr#v_#{variant1.id}"
          expect(page).not_to have_selector "table#new-products tr#v_#{variant2.id}"
          click_button "Back to my inventory"

          expect(page).to have_selector "table#variant-overrides tr#v_#{variant1.id}"
          expect(page).not_to have_selector "table#variant-overrides tr#v_#{variant2.id}"

          first("div#views-dropdown").click
          first("div#views-dropdown div.menu div.menu_item", text: "Hidden Products").click

          expect(page).not_to have_selector "table#hidden-products tr#v_#{variant1.id}"
          expect(page).to have_selector "table#hidden-products tr#v_#{variant2.id}"
        end
      end
    end
  end

  context "as the manager of a farm shop" do
    it "shows more than 100 products in my inventory" do
      supplier = create(:supplier_enterprise, sells: "own")
      inventory_items = (1..101).map do
        product = create(:simple_product, supplier_id: supplier.id)
        InventoryItem.create!(
          enterprise: supplier,
          variant: product.variants.first
        )
      end
      first_variant = inventory_items.first.variant
      last_variant = inventory_items.last.variant
      first_variant.product.update!(name: "A First Product")
      last_variant.product.update!(name: "Z Last Product")
      login_as supplier.users.first
      visit admin_inventory_path

      expect(page).to have_text first_variant.name
      expect(page).to have_text first_variant.supplier.name
      expect(page).to have_selector "tr.product", count: 10
      expect(page).to have_button "Show more"
      expect(page).to have_button "Show all (91  More)"

      click_button "Show all (91  More)"
      expect(page).to have_selector "tr.product", count: 101
      expect(page).to have_text last_variant.name
    end
  end

  def select_on_demand(variant, value_sym)
    option_label = I18n.t(value_sym, scope: "js.variant_overrides.on_demand")
    select option_label, from: "variant-overrides-#{variant.id}-on_demand"
  end
end
