# frozen_string_literal: true

require 'system_helper'

RSpec.describe 'Subscriptions' do
  include AdminHelper
  include AuthenticationHelper
  include WebHelper
  include SubscriptionHelper

  context "as an enterprise user" do
    let!(:user) { create(:user) }
    let!(:shop) { create(:distributor_enterprise, owner: user, enable_subscriptions: true) }
    let!(:shop2) { create(:distributor_enterprise, owner: user, enable_subscriptions: true) }
    let!(:shop_unmanaged) { create(:distributor_enterprise, enable_subscriptions: true) }

    before { login_as user }

    context 'listing subscriptions' do
      let!(:subscription) {
        create(:subscription, shop:, with_items: true, with_proxy_orders: true)
      }
      let!(:customer) { create(:customer, first_name: "Timmy", last_name: "Test") }
      let!(:other_subscription) {
        create(:subscription, shop:, customer:, with_items: true,
                              with_proxy_orders: true)
      }
      let!(:subscription2) {
        create(:subscription, shop: shop2, with_items: true, with_proxy_orders: true)
      }
      let!(:subscription_unmanaged) {
        create(:subscription, shop: shop_unmanaged, with_items: true, with_proxy_orders: true)
      }

      before do
        subscription.update(shipping_fee_estimate: 3.5)
        subscription.subscription_line_items.each do |sli|
          sli.update(price_estimate: 5)
        end
        visit admin_subscriptions_path
      end

      context "for pre-existing subscriptions" do
        it "passes the smoke test" do
          expect(page).to have_select2 "shop_id", with_options: [shop.name, shop2.name],
                                                  without_options: [shop_unmanaged.name]

          select2_select shop2.name, from: "shop_id"

          # Loads the right subscriptions
          expect(page).to have_selector "tr#so_#{subscription2.id}"
          expect(page).not_to have_selector "tr#so_#{subscription.id}"
          expect(page).not_to have_selector "tr#so_#{subscription_unmanaged.id}"
          within "tr#so_#{subscription2.id}" do
            expect(page).to have_selector "td.customer", text: subscription2.customer.email
          end

          # Changing Shops
          select2_select shop.name, from: "shop_id"

          # Loads the right subscriptions
          expect(page).to have_selector "tr#so_#{subscription.id}"
          expect(page).not_to have_selector "tr#so_#{subscription2.id}"
          expect(page).not_to have_selector "tr#so_#{subscription_unmanaged.id}"
          within "tr#so_#{subscription.id}" do
            expect(page).to have_selector "td.customer", text: subscription.customer.email
          end

          # Using the Quick Search
          expect(page).to have_selector "tr#so_#{subscription.id}"
          expect(page).to have_selector "tr#so_#{other_subscription.id}"

          # Using the Quick Search: no result
          fill_in 'query', with: 'blah blah blah'
          expect(page).not_to have_selector "tr#so_#{subscription.id}"
          expect(page).not_to have_selector "tr#so_#{other_subscription.id}"

          # Using the Quick Search: filter by email
          fill_in 'query', with: other_subscription.customer.email
          expect(page).to have_selector "tr#so_#{other_subscription.id}"
          expect(page).not_to have_selector "tr#so_#{subscription.id}"

          # Using the Quick Search: filter by first_name
          fill_in 'query', with: other_subscription.customer.first_name
          expect(page).to have_selector "tr#so_#{other_subscription.id}"
          expect(page).not_to have_selector "tr#so_#{subscription.id}"

          # Using the Quick Search: filter by last_name
          fill_in 'query', with: other_subscription.customer.last_name
          expect(page).to have_selector "tr#so_#{other_subscription.id}"
          expect(page).not_to have_selector "tr#so_#{subscription.id}"

          # Using the Quick Search: reset filter
          fill_in 'query', with: ''
          expect(page).to have_selector "tr#so_#{subscription.id}"
          expect(page).to have_selector "tr#so_#{other_subscription.id}"

          # Toggling columns
          expect(page).to have_selector "th.customer"
          expect(page).to have_content subscription.customer.email
          toggle_columns "Customer"
          expect(page).not_to have_selector "th.customer"
          expect(page).not_to have_content subscription.customer.email

          # Viewing Products
          open_subscription_products_panel

          within "#subscription-line-items" do
            expect(page).to have_selector "span#order_subtotal", text: "$15.00" # 3 x $5 items
            expect(page).to have_selector "span#order_fees", text: "$3.50" # $3.5 shipping
            # 3 x $5 items + $3.5 shipping
            expect(page).to have_selector "span#order_form_total", text: "$18.50"
          end

          # Viewing Orders
          within "tr#so_#{subscription.id}" do
            expect(page).to have_selector "td.orders.panel-toggle", text: 1
            page.find("td.orders.panel-toggle").click
          end

          within ".subscription-orders" do
            expect(page).to have_selector "tr.proxy_order", count: 1
            expect(page).to have_content "$18.50" # 3 x $5 items + $3.5 shipping

            proxy_order = subscription.proxy_orders.first
            within "tr#po_#{proxy_order.id}" do
              expect(page).not_to have_content 'CANCELLED'
              accept_alert 'Are you sure?' do
                find("a.cancel-order").click
              end
              expect(page).to have_content 'CANCELLED'
              expect(proxy_order.reload.canceled_at).to be_within(5.seconds).of Time.zone.now

              # Resuming an order
              accept_alert 'Are you sure?' do
                find("a.resume-order").click
              end
              # Note: the order itself was not complete when 'cancelled', so state remained as cart
              expect(page).to have_content 'PENDING'
              expect(proxy_order.reload.canceled_at).to be nil
            end
          end

          # Pausing a subscription
          within "tr#so_#{subscription.id}" do
            find("a.pause-subscription").click
          end
          click_button "Yes, I'm sure"
          within "tr#so_#{subscription.id}" do
            expect(page).to have_selector ".state.paused", text: "PAUSED"
            expect(subscription.reload.paused_at).to be_within(5.seconds).of Time.zone.now
          end

          # Unpausing a subscription
          within "tr#so_#{subscription.id}" do
            find("a.unpause-subscription").click
          end
          click_button "Yes, I'm sure"
          within "tr#so_#{subscription.id}" do
            expect(page).to have_selector ".state.active", text: "ACTIVE"
            expect(subscription.reload.paused_at).to be nil
          end

          # Cancelling a subscription
          within "tr#so_#{subscription.id}" do
            find("a.cancel-subscription").click
          end
          click_button "Yes, I'm sure"
          within "tr#so_#{subscription.id}" do
            expect(page).to have_selector ".state.canceled", text: "CANCELLED"
            expect(subscription.reload.canceled_at).to be_within(5.seconds).of Time.zone.now
          end
        end
      end

      context "editing subscription products quantity" do
        it "updates quantity" do
          select2_select shop.name, from: "shop_id"
          open_subscription_products_panel

          within "#sli_0" do
            fill_in 'quantity', with: "5"
          end

          page.find("a.button.update").click
          expect(page).to have_content 'SAVED'
        end
      end

      def open_subscription_products_panel
        within "tr#so_#{subscription.id}" do
          expect(page).to have_selector "td.items.panel-toggle", text: 3
          page.find("td.items.panel-toggle").click
        end
      end
    end

    context 'when creating a new subscription' do
      let(:address) { create(:address) }
      let!(:customer_user) { create(:user) }
      let!(:credit_card1) {
        create(:stored_credit_card, user: customer_user, cc_type: 'visa', last_digits: 1111,
                                    month: 10, year: 2030)
      }
      let!(:customer) {
        create(:customer, enterprise: shop, bill_address: address, user: customer_user,
                          allow_charges: true)
      }
      let!(:test_product) { create(:product) }
      let!(:test_variant) {
        create(:variant, product: test_product, unit_value: "100", price: 12.00, supplier: shop)
      }
      let!(:shop_product) { create(:product) }
      let!(:shop_variant) {
        create(:variant, product: shop_product, unit_value: "1000", price: 6.00, supplier: shop)
      }
      let!(:enterprise_fee) { create(:enterprise_fee, amount: 1.75) }
      let!(:order_cycle) {
        create(:simple_order_cycle, coordinator: shop, orders_open_at: 2.days.from_now,
                                    orders_close_at: 7.days.from_now)
      }
      let!(:outgoing_exchange) {
        order_cycle.exchanges.create(sender: shop, receiver: shop,
                                     variants: [test_variant, shop_variant],
                                     enterprise_fees: [enterprise_fee])
      }
      let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
      let!(:payment_method) {
        create(:stripe_sca_payment_method, name: 'Credit Card', distributors: [shop])
      }
      let!(:shipping_method) { create(:shipping_method, distributors: [shop]) }

      before do
        visit admin_subscriptions_path
        page.find("#new-subscription").click
        tomselect_select shop.name, from: "subscription[shop_id]"
        click_button "Continue"
      end

      context 'on first page' do
        before do
          select2_select customer.email, from: 'customer_id'
          select2_select schedule.name, from: 'schedule_id'
          select2_select payment_method.name, from: 'payment_method_id'
          select2_select shipping_method.name, from: 'shipping_method_id'
        end

        context 'and date field is not filled' do
          it 'counts a can not be blank content once' do
            click_button('Next')

            expect(page).to have_content 'can\'t be blank', count: 1
            expect(page).to have_content 'Oops! Please fill in all of the required fields...'
          end
        end

        context 'and date field is filled' do
          it 'goes to the next page and preload customer bill address' do
            find_field('begins_at').click
            choose_today_from_datepicker
            click_button('Next')

            expect(page).to have_content 'Billing Address'
            # Customer bill address has been pre-loaded
            expect(page).to have_input "bill_address_firstname", with: address.firstname
            expect(page).to have_input "bill_address_lastname", with: address.lastname
            expect(page).to have_input "bill_address_address1", with: address.address1
          end
        end
      end

      context 'on second page' do
        before do
          select2_select customer.email, from: 'customer_id'
          select2_select schedule.name, from: 'schedule_id'
          select2_select payment_method.name, from: 'payment_method_id'
          select2_select shipping_method.name, from: 'shipping_method_id'
          find_field('begins_at').click
          choose_today_from_datepicker
          click_button('Next')
        end

        context 'when clearing some elements of bill address' do
          before do
            # Clear some elements of bill address
            fill_in "bill_address_firstname", with: ''
            fill_in "bill_address_lastname", with: ''
            fill_in "bill_address_address1", with: ''
            fill_in "bill_address_city", with: ''
            fill_in "bill_address_zipcode", with: ''
            fill_in "bill_address_phone", with: ''
          end

          it 'counts 6 can not be blank messages' do
            click_button('Next')
            expect(page).to have_content 'can\'t be blank', count: 6
          end

          context 'and re-setting the billing address' do
            before do
              fill_in "bill_address_firstname", with: 'Freda'
              fill_in "bill_address_lastname", with: 'Figapple'
              fill_in "bill_address_address1", with: '7 Tempany Lane'
              fill_in "bill_address_city", with: 'Natte Yallock'
              fill_in "bill_address_zipcode", with: '3465'
              fill_in "bill_address_phone", with: '0400 123 456'
              select2_select "Australia", from: "bill_address_country_id"
              select2_select "Victoria", from: "bill_address_state_id"
            end

            context 'and using copy button to fill in ship address' do
              before { click_link "Copy" }

              it 'has input with ship address values' do
                expect(page).to have_input "ship_address_firstname", with: 'Freda'
                expect(page).to have_input "ship_address_lastname", with: 'Figapple'
                expect(page).to have_input "ship_address_address1", with: '7 Tempany Lane'
              end
            end
          end
        end
      end

      context 'on third page' do
        before do
          select2_select customer.email, from: 'customer_id'
          select2_select schedule.name, from: 'schedule_id'
          select2_select payment_method.name, from: 'payment_method_id'
          select2_select shipping_method.name, from: 'shipping_method_id'
          find_field('begins_at').click
          choose_today_from_datepicker
          click_button('Next')
          click_button('Next')
        end

        it 'has content NAME OR SKU' do
          expect(page).to have_content 'NAME OR SKU'
        end

        context 'and click next button without adding at least one product' do
          before { click_button('Next') }

          it 'has content Please add at least one product' do
            expect(page).to have_content 'Please add at least one product'
          end
        end

        context 'with a product' do
          before { add_variant_to_subscription test_variant, 2 }

          it 'has description, price estimates, quantity and total' do
            within 'table#subscription-line-items tr.item', match: :first do
              expect(page).to have_selector '.description',
                                            text: "#{test_product.name} - #{test_variant.full_name}"
              expect(page).to have_selector 'td.price', text: "$13.75"
              expect(page).to have_input 'quantity', with: "2"
              expect(page).to have_selector 'td.total', text: "$27.50"
            end
          end

          context 'and deleting the existing product' do
            before do
              within 'table#subscription-line-items tr.item', match: :first do
                find("a.delete-item").click
              end
            end

            it 'has content Please add at least one product and subscription does not change' do
              click_button('Next')

              expect{
                click_button('Create Subscription')
                expect(page).to have_content 'Please add at least one product'
              }.not_to change { Subscription.count }
            end

            context 'and adding a new product' do
              before do
                click_button('Next')
                click_button('edit-products')
                add_variant_to_subscription shop_variant, 3
              end

              it 'has selectors for description, price, quantity and total' do
                description = "#{shop_product.name} - #{shop_variant.full_name}"

                within 'table#subscription-line-items tr.item', match: :first do
                  expect(page).to have_selector '.description',
                                                text: description
                  expect(page).to have_selector 'td.price', text: "$7.75"
                  expect(page).to have_input 'quantity', with: "3"
                  expect(page).to have_selector 'td.total', text: "$23.25"
                end
              end

              context 'and click next button' do
                before { click_button('Next') }

                it 'has current path as admin_subscriptions_path and counts by one subscription' do
                  expect{
                    click_button('Create Subscription')
                    expect(page).to have_current_path admin_subscriptions_path
                  }.to change { Subscription.count }.by(1)
                end

                context 'and click Create Subscription button' do
                  before do
                    click_button('Create Subscription')
                    select2_select shop.name, from: "shop_id"
                  end

                  it 'has selector td.items.panel-toggle' do
                    expect(page).to have_selector "td.items.panel-toggle"
                  end

                  it 'has selector for price, input for quantity and selector for total price' do
                    description = "#{shop_product.name} - #{shop_variant.full_name}"
                    subscription = Subscription.last
                    subscription_line_item = subscription.subscription_line_items.first

                    first("td.items.panel-toggle").click

                    within 'table#subscription-line-items tr.item', match: :first do
                      expect(page).to have_selector '.description',
                                                    text: description
                      expect(page).to have_selector 'td.price', text: "$7.75"
                      expect(page).to have_input 'quantity', with: "3"
                      expect(page).to have_selector 'td.total', text: "$23.25"
                    end

                    expect(subscription.customer).to eq customer
                    expect(subscription.schedule).to eq schedule
                    expect(subscription.payment_method).to eq payment_method
                    expect(subscription.shipping_method).to eq shipping_method
                    expect(subscription.bill_address.firstname).to eq 'John'
                    expect(subscription.ship_address.firstname).to eq 'John'
                    expect(subscription.subscription_line_items.count).to eq 1
                    expect(subscription_line_item.variant).to eq shop_variant
                    expect(subscription_line_item.quantity).to eq 3
                  end
                end
              end
            end
          end
        end
      end
    end

    context 'editing an existing subscription' do
      let!(:customer) { create(:customer, enterprise: shop) }
      let!(:product1) { create(:product) }
      let!(:product2) { create(:product) }
      let!(:product3) { create(:product) }
      let!(:variant1) {
        create(:variant, product: product1, unit_value: '100', price: 12.00, supplier: shop)
      }
      let!(:variant2) {
        create(:variant, product: product2, unit_value: '1000', price: 6.00, supplier: shop)
      }
      let!(:variant3) {
        create(:variant, product: product3, unit_value: '10000', price: 22.00, supplier: shop)
      }
      let!(:enterprise_fee) { create(:enterprise_fee, amount: 1.75) }
      let!(:order_cycle) {
        create(:simple_order_cycle, coordinator: shop, orders_open_at: 2.days.from_now,
                                    orders_close_at: 7.days.from_now)
      }
      let!(:outgoing_exchange) {
        order_cycle.exchanges.create(sender: shop, receiver: shop, variants: [variant1, variant2],
                                     enterprise_fees: [enterprise_fee])
      }
      let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
      let!(:variant3_oc) {
        create(:simple_order_cycle, coordinator: shop, orders_open_at: 2.days.from_now,
                                    orders_close_at: 7.days.from_now)
      }
      let!(:variant3_ex) {
        variant3_oc.exchanges.create(sender: shop, receiver: shop, variants: [variant3])
      }
      let!(:payment_method) { create(:payment_method, distributors: [shop]) }
      let!(:stripe_payment_method) {
        create(:stripe_sca_payment_method, name: 'Credit Card', distributors: [shop])
      }
      let!(:shipping_method) { create(:shipping_method, distributors: [shop]) }
      let!(:subscription) {
        create(:subscription,
               shop:,
               customer:,
               schedule:,
               payment_method:,
               shipping_method:,
               subscription_line_items: [create(:subscription_line_item, variant: variant1,
                                                                         quantity: 2,
                                                                         price_estimate: 13.75)],
               with_proxy_orders: true)
      }

      it "passes the smoke test" do
        visit edit_admin_subscription_path(subscription)

        # Customer and Schedule cannot be edited
        click_button 'edit-details'
        expect(page).to have_selector '#s2id_customer_id.select2-container-disabled'
        expect(page).to have_selector '#s2id_schedule_id.select2-container-disabled'

        # Can't use a Stripe payment method because customer does not allow it
        select2_select stripe_payment_method.name, from: 'payment_method_id'
        expect(page).to have_content 'Charges are not allowed by this customer'
        click_button 'Save Changes'
        expect(page).to have_content 'Credit card charges are not allowed by this customer'
        select2_select payment_method.name, from: 'payment_method_id'
        click_button 'Review'

        # Existing products should be visible
        click_button 'edit-products'
        within "#sli_0" do
          expect(page).to have_selector '.description',
                                        text: "#{product1.name} - #{variant1.full_name}"
          expect(page).to have_selector 'td.price', text: "$13.75"
          expect(page).to have_input 'quantity', with: "2"
          expect(page).to have_selector 'td.total', text: "$27.50"

          # Remove variant1 from the subscription
          find("a.delete-item").click
        end

        # Attempting to submit without a product
        click_button 'Save Changes'
        expect(page).to have_content 'Please add at least one product'

        # Add variant2 to the subscription
        add_variant_to_subscription(variant2, 1)
        within "#sli_0" do
          expect(page).to have_selector '.description',
                                        text: "#{product2.name} - #{variant2.full_name}"
          expect(page).to have_selector 'td.price', text: "$7.75"
          expect(page).to have_input 'quantity', with: "1"
          expect(page).to have_selector 'td.total', text: "$7.75"
        end

        # Total should be $7.75
        expect(page).to have_selector '#order_form_total', text: "$7.75"

        # Add variant3 to the subscription (even though it is not available)
        add_variant_to_subscription(variant3, 1)
        within "#sli_1" do
          expect(page).to have_selector '.description',
                                        text: "#{product3.name} - #{variant3.full_name}"
          expect(page).to have_selector 'td.price', text: "$22.00"
          expect(page).to have_input 'quantity', with: "1"
          expect(page).to have_selector 'td.total', text: "$22.00"
        end

        # Total should be $29.75
        expect(page).to have_selector '#order_form_total', text: "$29.75"

        # Remove variant3 from the subscription
        within '#sli_1' do
          find("a.delete-item").click
        end

        click_button 'Save Changes'
        expect(page).to have_current_path admin_subscriptions_path

        select2_select shop.name, from: "shop_id"
        expect(page).to have_selector "td.items.panel-toggle"
        first("td.items.panel-toggle").click

        # Total should be $7.75
        expect(page).to have_selector '#order_form_total', text: "$7.75"
        expect(page).to have_selector 'tr.item', count: 1
        expect(subscription.reload.subscription_line_items.length).to eq 1
        expect(subscription.subscription_line_items.first.variant).to eq variant2
      end

      context "with initialised order that has been changed" do
        let(:proxy_order) { subscription.proxy_orders.first }
        let(:order) { proxy_order.initialise_order! }
        let(:line_item) { order.line_items.first }

        before { line_item.update(quantity: 3) }

        it "reports issues encountered during the update" do
          visit edit_admin_subscription_path(subscription)
          click_button 'edit-products'

          within "#sli_0" do
            fill_in 'quantity', with: "1"
          end

          click_button 'Save Changes'
          expect(page).to have_content 'Saved'

          expect(page).to have_selector "#order_update_issues_dialog .message",
                                        text: 'Some orders could not be automatically updated, ' \
                                              'this is most likely because they have been ' \
                                              'manually edited. Please review the issues listed ' \
                                              'below and make any adjustments to individual ' \
                                              'orders if required.'
        end
      end
    end
  end
end
