require 'test_helper'

module Workarea
  module Admin
    class ReportsSystemTest < SystemTest
      include Admin::IntegrationTest

      def test_average_order_value
        Metrics::SalesByDay.inc(
          at: Time.zone.local(2018, 11, 14),
          orders: 1,
          revenue: 5
        )

        Metrics::SalesByDay.inc(
          at: Time.zone.local(2018, 10, 30),
          orders: 2,
          revenue: 6
        )

        travel_to Time.zone.local(2018, 11, 20)

        visit admin.average_order_value_report_path
        assert(page.has_content?('2018-11'))
        assert(page.has_content?('2018-10'))
        assert(page.has_content?('1'))
        assert(page.has_content?('5'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_ordered_text?('2018-10', '2018-11'))

        click_link "#{t('workarea.admin.fields.orders')} ↓"
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↑"))
        assert(page.has_ordered_text?('2018-11', '2018-10'))

        select 'Day', from: 'group_by'
        assert(page.has_content?('2018-11-14'))
        assert(page.has_content?('2018-10-30'))
        assert(page.has_content?('1'))
        assert(page.has_content?('5'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))
      end

      def test_first_time_vs_returning_sales_test
        Metrics::SalesByDay.inc(
          at: Time.zone.local(2018, 11, 14),
          orders: 5,
          returning_orders: 2
        )

        Metrics::SalesByDay.inc(
          at: Time.zone.local(2018, 10, 30),
          orders: 2,
          returning_orders: 1
        )

        travel_to Time.zone.local(2018, 11, 20)

        visit admin.first_time_vs_returning_sales_report_path
        assert(page.has_content?('2018-11'))
        assert(page.has_content?('2018-10'))
        assert(page.has_content?('40%'))
        assert(page.has_content?('5'))
        assert(page.has_content?('50%'))
        assert(page.has_content?('1'))

        click_link t('workarea.admin.fields.percent_returning')
        assert(page.has_ordered_text?('2018-10', '2018-11'))

        click_link "#{t('workarea.admin.fields.percent_returning')} ↓"
        assert(page.has_content?("#{t('workarea.admin.fields.percent_returning')} ↑"))
        assert(page.has_ordered_text?('2018-11', '2018-10'))

        select 'Day', from: 'group_by'
        assert(page.has_content?('2018-11-14'))
        assert(page.has_content?('2018-10-30'))
        assert(page.has_content?('40%'))
        assert(page.has_content?('5'))
        assert(page.has_content?('50%'))
        assert(page.has_content?('1'))
      end

      def test_insights
        hot = create_hot_products
        cold = create_cold_products

        visit admin.insights_report_path
        assert(page.has_content?(hot.results.first['product_id']))

        [hot, cold].each do |insight|
          insight.results.each { |r| create_product(id: r['product_id']) }
        end

        visit admin.insights_report_path
        assert(page.has_content?('Test Product'))

        select t('workarea.admin.insights.hot_products.title'), from: 'type'
        assert(page.has_content?(t('workarea.admin.insights.hot_products.info')))
        assert(page.has_no_content?(t('workarea.admin.insights.cold_products.info')))
      end

      def test_customers
        Metrics::User.save_order(email: 'once@workarea.com', revenue: 10.to_m)
        Metrics::User.save_order(email: 'once@workarea.com', revenue: 20.to_m)
        Metrics::User.save_order(email: 'twice@workarea.com', revenue: 10.to_m)
        Metrics::User.save_order(email: 'twice@workarea.com', revenue: 20.to_m)
        Metrics::User.save_order(email: 'twice@workarea.com', revenue: 30.to_m)
        create_user(email: 'once@workarea.com', first_name: 'Ben', last_name: 'Crouse')

        visit admin.customers_report_path
        assert(page.has_content?('Ben Crouse'))
        assert(page.has_content?('twice@workarea.com'))
        assert(page.has_content?('15'))
        assert(page.has_content?('20'))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↓"))
        assert(page.has_ordered_text?('twice@workarea.com', 'Ben Crouse'))

        click_link "#{t('workarea.admin.fields.orders')} ↓"
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↑"))
        assert(page.has_ordered_text?('Ben Crouse', 'twice@workarea.com'))
      end

      def test_sales_by_category
        category = create_category(name: 'Foo')

        Metrics::CategoryByDay.inc(key: { category_id: category.id }, orders: 1, units_sold: 5)
        Metrics::CategoryByDay.inc(key: { category_id: 'bar' }, orders: 2, units_sold: 3)

        visit admin.sales_by_category_report_path
        assert(page.has_content?('Foo'))
        assert(page.has_content?(t('workarea.admin.reports.unknown')))
        assert(page.has_content?('1'))
        assert(page.has_content?('5'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↓"))
        assert(page.has_ordered_text?(t('workarea.admin.reports.unknown'), 'Foo'))

        click_link t('workarea.admin.fields.units_sold')
        assert(page.has_content?("#{t('workarea.admin.fields.units_sold')} ↓"))
        assert(page.has_ordered_text?('Foo', t('workarea.admin.reports.unknown')))

        click_link t('workarea.admin.fields.units_sold')
        assert(page.has_content?("#{t('workarea.admin.fields.units_sold')} ↑"))
        assert(page.has_ordered_text?(t('workarea.admin.reports.unknown'), 'Foo'))
      end

      def test_sales_by_country
        Metrics::CountryByDay.inc(key: { country: 'US' }, orders: 1, units_sold: 5)
        Metrics::CountryByDay.inc(key: { country: 'bar' }, orders: 2, units_sold: 3)

        visit admin.sales_by_country_report_path
        assert(page.has_content?(Country['US'].name))
        assert(page.has_content?('bar'))
        assert(page.has_content?('1'))
        assert(page.has_content?('5'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))

        click_link t('workarea.admin.fields.units_sold')
        assert(page.has_content?("#{t('workarea.admin.fields.units_sold')} ↓"))
        assert(page.has_ordered_text?(Country['US'].name, 'bar'))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↓"))
        assert(page.has_ordered_text?('bar', Country['US'].name))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↑"))
        assert(page.has_ordered_text?(Country['US'].name, 'bar'))
      end

      def test_sales_by_discount
        discount = create_order_total_discount(name: 'Foo')

        Metrics::DiscountByDay.inc(key: { discount_id: discount.id }, orders: 1)
        Metrics::DiscountByDay.inc(key: { discount_id: 'bar' }, orders: 2)

        visit admin.sales_by_discount_report_path
        assert(page.has_content?('Foo'))
        assert(page.has_content?(t('workarea.admin.reports.unknown')))
        assert(page.has_content?('1'))
        assert(page.has_content?('2'))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↓"))
        assert(page.has_ordered_text?(t('workarea.admin.reports.unknown'), 'Foo'))
      end

      def test_sales_by_product
        create_product(id: 'foo', name: 'Foo')

        Metrics::ProductByDay.inc(key: { product_id: 'foo' }, orders: 1, units_sold: 5)
        Metrics::ProductByDay.inc(key: { product_id: 'bar' }, orders: 2, units_sold: 3)

        visit admin.sales_by_product_report_path
        assert(page.has_content?('Foo'))
        assert(page.has_content?('bar'))
        assert(page.has_content?('1'))
        assert(page.has_content?('5'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↓"))
        assert(page.has_ordered_text?('bar', 'Foo'))

        click_link t('workarea.admin.fields.units_sold')
        assert(page.has_content?("#{t('workarea.admin.fields.units_sold')} ↓"))
        assert(page.has_ordered_text?('Foo', 'bar'))

        click_link t('workarea.admin.fields.units_sold')
        assert(page.has_content?("#{t('workarea.admin.fields.units_sold')} ↑"))
        assert(page.has_ordered_text?('bar', 'Foo'))
      end

      def test_sales_by_sku
        create_product(name: 'Foo', variants: [{ sku: 'foo' }])

        Metrics::SkuByDay.inc(key: { sku: 'foo' }, orders: 1, units_sold: 5)
        Metrics::SkuByDay.inc(key: { sku: 'bar' }, orders: 2, units_sold: 3)

        visit admin.sales_by_sku_report_path
        assert(page.has_content?('foo'))
        assert(page.has_content?('bar'))
        assert(page.has_content?('1'))
        assert(page.has_content?('5'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↓"))
        assert(page.has_ordered_text?('bar', 'foo'))

        click_link t('workarea.admin.fields.units_sold')
        assert(page.has_content?("#{t('workarea.admin.fields.units_sold')} ↓"))
        assert(page.has_ordered_text?('foo', 'bar'))

        click_link t('workarea.admin.fields.units_sold')
        assert(page.has_content?("#{t('workarea.admin.fields.units_sold')} ↑"))
        assert(page.has_ordered_text?('bar', 'foo'))
      end

      def test_sales_by_traffic_referrer
        Metrics::TrafficReferrerByDay.inc(
          key: { medium: 'search', source: 'Google' },
          orders: 1,
          units_sold: 2
        )

        Metrics::TrafficReferrerByDay.inc(
          key: { medium: 'social', source: 'Facebook' },
          orders: 3,
          units_sold: 4
        )

        Metrics::TrafficReferrerByDay.inc(
          key: { medium: 'social', source: 'Twitter' },
          orders: 5,
          units_sold: 6
        )

        visit admin.sales_by_traffic_referrer_report_path
        assert(page.has_content?('Google'))
        assert(page.has_content?('Facebook'))
        assert(page.has_content?('Twitter'))
        assert(page.has_content?('Social'))
        assert(page.has_content?('Search'))
        assert(page.has_content?('1'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))
        assert(page.has_content?('4'))
        assert(page.has_content?('5'))
        assert(page.has_content?('6'))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↓"))
        assert(page.has_ordered_text?('Twitter', 'Facebook', 'Google'))
        assert(page.has_ordered_text?('5', '3', '1'))
        assert(page.has_ordered_text?('6', '4', '2'))

        click_link t('workarea.admin.fields.source')
        assert(page.has_content?("#{t('workarea.admin.fields.source')} ↓"))
        assert(page.has_ordered_text?('Twitter', 'Google', 'Facebook'))

        click_link t('workarea.admin.fields.medium')
        assert(page.has_content?("#{t('workarea.admin.fields.medium')} ↓"))
        assert(page.has_ordered_text?('Social', 'Search'))
      end

      def test_sales_by_tender
        Metrics::TenderByDay.inc(key: { tender: 'credit_card' }, orders: 1, revenue: 100)
        Metrics::TenderByDay.inc(key: { tender: 'store_credit' }, orders: 2, revenue: 24)

        visit admin.sales_by_tender_report_path
        assert(page.has_content?('Credit Card'))
        assert(page.has_content?('Store Credit'))
        assert(page.has_content?('1'))
        assert(page.has_content?('$100.00'))
        assert(page.has_content?('2'))
        assert(page.has_content?('$24.00'))

        click_link t('workarea.admin.fields.revenue')
        assert(page.has_content?("#{t('workarea.admin.fields.revenue')} ↓"))
        assert(page.has_ordered_text?('Credit Card', 'Store Credit'))

        click_link t('workarea.admin.fields.revenue')
        assert(page.has_content?("#{t('workarea.admin.fields.revenue')} ↑"))
        assert(page.has_ordered_text?('Store Credit', 'Credit Card'))
      end

      def test_sales_over_time
        Metrics::SalesByDay.inc(
          at: Time.zone.local(2018, 11, 14),
          orders: 1,
          units_sold: 5,
          revenue: 25
        )

        Metrics::SalesByDay.inc(
          at: Time.zone.local(2018, 10, 30),
          orders: 2,
          units_sold: 3,
          revenue: 30
        )

        travel_to Time.zone.local(2018, 11, 20)

        visit admin.sales_over_time_report_path
        assert(page.has_content?('2018-11'))
        assert(page.has_content?('2018-10'))
        assert(page.has_content?('1'))
        assert(page.has_content?('5'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))

        click_link t('workarea.admin.fields.orders')
        assert(page.has_content?("#{t('workarea.admin.fields.orders')} ↓"))
        assert(page.has_ordered_text?('2018-10', '2018-11'))

        click_link t('workarea.admin.fields.units_sold')
        assert(page.has_content?("#{t('workarea.admin.fields.units_sold')} ↓"))
        assert(page.has_ordered_text?('2018-11', '2018-10'))

        click_link t('workarea.admin.fields.units_sold')
        assert(page.has_content?("#{t('workarea.admin.fields.units_sold')} ↑"))
        assert(page.has_ordered_text?('2018-10', '2018-11'))

        select 'Day', from: 'group_by'
        assert(page.has_content?('2018-11-14'))
        assert(page.has_content?('2018-10-30'))
        assert(page.has_content?('1'))
        assert(page.has_content?('5'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))
      end

      def test_searches
        2.times { Metrics::SearchByDay.save_search('foo', 3) }
        Metrics::SearchByDay.save_search('bar', 4)

        Metrics::SearchByDay.inc(
          key: { query_id: 'foo' },
          orders: 1,
          units_sold: 5,
          revenue: 25
        )

        Metrics::SearchByDay.inc(
          key: { query_id: 'bar' },
          orders: 2,
          units_sold: 3,
          revenue: 30
        )

        3.times { Metrics::SearchByDay.save_search('baz', 0) }
        4.times { Metrics::SearchByDay.save_search('qux', 0) }

        visit admin.searches_report_path
        assert(page.has_content?('foo'))
        assert(page.has_content?('bar'))
        assert(page.has_content?('baz'))
        assert(page.has_content?('qux'))

        select t('workarea.admin.reports.searches.filters.with_results'),
               from: :results_filter

        assert(page.has_content?('foo'))
        assert(page.has_content?('bar'))
        assert(page.has_no_content?('baz'))
        assert(page.has_no_content?('qux'))
        assert(page.has_content?('1'))
        assert(page.has_content?('2'))
        assert(page.has_content?('3'))
        assert(page.has_content?('4'))
        assert(page.has_content?('25'))
        assert(page.has_content?('30'))

        select t('workarea.admin.reports.searches.filters.without_results'),
               from: :results_filter

        assert(page.has_no_content?('foo'))
        assert(page.has_no_content?('bar'))
        assert(page.has_content?('baz'))
        assert(page.has_content?('qux'))
        assert(page.has_content?('3'))
        assert(page.has_content?('4'))

        select t('workarea.admin.reports.searches.filters.all'),
               from: :results_filter

        assert(page.has_content?('foo'))
        assert(page.has_content?('bar'))
        assert(page.has_content?('baz'))
        assert(page.has_content?('qux'))

        click_link "#{t('workarea.admin.fields.searches')} ↓"
        assert(page.has_content?("#{t('workarea.admin.fields.searches')} ↑"))
        assert(page.has_ordered_text?('bar', 'foo', 'baz', 'qux'))
        assert(page.has_ordered_text?('30', '25'))
      end

      def test_low_inventory
        skus = [
          create_inventory(id: 'ignore_sku', policy: 'ignore'),
          create_inventory(
            id: 'standard_low',
            policy: 'standard',
            available: Workarea.config.low_inventory_threshold - 1,
          ),
          create_inventory(
            id: 'backordered_low',
            policy: 'allow_backorder',
            available: Workarea.config.low_inventory_threshold - 2,
            backordered: 1,
          ),
          create_inventory(
            id: 'standard_ok',
            policy: 'standard',
            available: Workarea.config.low_inventory_threshold + 1,
          )
        ]

        visit admin.low_inventory_report_path

        assert(page.has_content?('standard_low'))
        assert(page.has_content?('backordered_low'))
        assert(page.has_no_content?('ignored_sku'))
        assert(page.has_no_content?('standard_ok'))

        product =
          create_product(variants: [{ sku: 'standard_ok', regular: 5.to_m }])

        complete_checkout(
          Order.new(
            email: 'test@workarea.com',
            items: [{ product_id: product.id, sku: 'standard_ok', quantity: 2 }]
          )
        )

        visit admin.low_inventory_report_path

        assert(page.has_content?('standard_ok'))
        assert(page.has_content?('standard_low'))
        assert(page.has_content?('backordered_low'))
      end

      def test_reports_chart
        yesterday = 1.day.ago
        last_week = 1.week.ago

        create_release(name: 'Foo Release', published_at: yesterday)

        visit admin.timeline_report_path

        # Since we don't explicitly depend on Chart.js, but rather depend on
        # ChartKick which depends on Chart.js, we want to make sure the library
        # still works as we upgrade ChartKick.
        assert_match(/class=('|")chartjs-render-monitor/, page.body)

        within '.timeline-report__sidebar' do
          assert_text 'Foo Release'
          click_link 'Foo Release'
        end

        within '.tooltipster-box' do
          assert_text 'Foo Release'
        end

        find('body').click # close tooltip

        click_link t('workarea.admin.reports.timeline.add_custom')

        within '.tooltipster-box' do
          fill_in 'custom_event[name]', with: 'Foo Event'
          fill_in 'custom_event_occurred_at_date', with: yesterday.strftime('%Y-%m-%d')
          click_button t('workarea.admin.reports.timeline.add_custom_event')
        end

        within '.timeline-report__event-group' do
          assert_text 'Foo Release'
          assert_text 'Foo Event'
          click_link 'Foo Event'
        end

        within '.tooltipster-box' do
          fill_in 'custom_event[name]', with: 'Bar Event'
          fill_in t('workarea.admin.js.datetime_picker.date'), with: last_week.strftime('%Y-%m-%d')
          click_button t('workarea.admin.reports.timeline.update_event')
        end

        within '.timeline-report__event-group:first-of-type' do
          refute_text 'Foo Release'
          refute_text 'Foo Event'
          assert_text 'Bar Event'
        end

        within '.timeline-report__event-group:last-of-type' do
          assert_text 'Foo Release'
          refute_text 'Foo Event'
          refute_text 'Bar Event'
        end
      end
    end
  end
end