import time
import uuid
import pandas as pd
from ..kawa_base_e2e_test import KawaBaseTest


class TestComputationHistoryReport(KawaBaseTest):

    @classmethod
    def setUpClass(cls):
        KawaBaseTest.setUpClass()
        unique_id = 'resource_{}'.format(uuid.uuid4())

        df = pd.DataFrame([
            {'category': 'A', 'value': 1},
            {'category': 'B', 'value': 2},
            {'category': 'C', 'value': 3},
        ])
        loader = cls.kawa.new_data_loader(df=df, datasource_name=unique_id)
        loader.create_datasource()
        datasource = loader.load_data(reset_before_insert=True)
        sheet = cls.kawa.commands.create_sheet(datasource=datasource, sheet_name=unique_id)
        cls.sheet_id = sheet.get('id')

        # Standalone layout: use the default layout
        cls.standalone_layout_id = sheet.get('layoutIds')[0]
        standalone_layout = cls.kawa.entities.layouts().get_entity_by_id(cls.standalone_layout_id)
        cls.standalone_layout_display_information = standalone_layout.get('displayInformation', {})

        # Dashboard layout: create a dashboard
        cls.dashboard_name = 'Dashboard for {}'.format(unique_id)
        builder = cls.kawa.dashboard(cls.dashboard_name)
        col = builder.create_section()
        widget = col.table(title='Test table', sheet_id=cls.sheet_id)
        builder.publish()
        cls.dashboard_id = builder._dashboard_id
        cls.dashboard_layout_id = widget.layout_id
        dashboard_layout = cls.kawa.entities.layouts().get_entity_by_id(cls.dashboard_layout_id)
        cls.dashboard_display_information = cls.kawa.entities.dashboards().get_entity_by_id(cls.dashboard_id).get('displayInformation', {})
        cls.dashboard_layout_display_information = dashboard_layout.get('displayInformation', {})

        principals = cls.kawa.entities.principals().list_entities()
        admin_email = cls.kawa.get_current_user().get('email')
        cls.admin_principal_id = next(
            (p.get('id') for p in principals if p.get('email') == admin_email), None
        )

    def test_standalone_layout_appears_in_history(self):
        # given
        start_ms = int(time.time() * 1000)
        self.kawa.sheet(sheet_id=self.sheet_id).view_id(self.standalone_layout_id).compute()

        # when
        r = self.kawa.reporting().generate_computation_views_report(from_ms=start_ms)

        # then
        match = r[r['layout_id'] == self.standalone_layout_id]
        self.assertEqual(len(match), 1)
        row = match.iloc[0]
        self.assertEqual(row['layout_id'], self.standalone_layout_id)
        self.assertEqual(row['layout_display_information'], self.standalone_layout_display_information)
        self.assertGreater(row['timestamp'], start_ms)
        self.assertIsNone(row['dashboard_id'])
        self.assertIsNone(row['dashboard_display_information'])
        self.assertIsNone(row['application_id'])
        self.assertIsNone(row['application_display_information'])

    def test_dashboard_layout_appears_in_history_with_dashboard_info(self):
        # given
        start_ms = int(time.time() * 1000)
        self.kawa.sheet(sheet_id=self.sheet_id).view_id(self.dashboard_layout_id).compute()

        # when
        r = self.kawa.reporting().generate_computation_views_report(from_ms=start_ms)

        # then
        match = r[r['layout_id'] == self.dashboard_layout_id]
        self.assertEqual(len(match), 1)
        row = match.iloc[0]
        self.assertEqual(row['layout_id'], self.dashboard_layout_id)
        self.assertEqual(row['layout_display_information'], self.dashboard_layout_display_information)
        self.assertEqual(row['dashboard_id'], self.dashboard_id)
        self.assertEqual(row['dashboard_display_information'], self.dashboard_display_information)
        self.assertIsNone(row['application_id'])
        self.assertIsNone(row['application_display_information'])

    def test_history_captures_computations_from_different_users(self):
        # given
        start_ms = int(time.time() * 1000)
        self.kawa.sheet(sheet_id=self.sheet_id).view_id(self.standalone_layout_id).compute()
        self.kawa_second_user.sheet(sheet_id=self.sheet_id).view_id(self.standalone_layout_id).compute()

        # when
        r = self.kawa.reporting().generate_computation_views_report(from_ms=start_ms)

        # then
        match = r[r['layout_id'] == self.standalone_layout_id]
        self.assertEqual(len(match), 2)
        self.assertEqual(len(set(match['user_id'].tolist())), 2)
        self.assertEqual(len(set(match['user_email'].tolist())), 2)

    def test_entity_type_filter_layout_excludes_dashboard_computations(self):
        # given
        start_ms = int(time.time() * 1000)
        self.kawa.sheet(sheet_id=self.sheet_id).view_id(self.standalone_layout_id).compute()
        self.kawa.sheet(sheet_id=self.sheet_id).view_id(self.dashboard_layout_id).compute()

        # when
        r = self.kawa.reporting().generate_computation_views_report(from_ms=start_ms, entity_type='layout')

        # then
        self.assertTrue((r['layout_id'] == self.standalone_layout_id).any())
        self.assertFalse((r['layout_id'] == self.dashboard_layout_id).any())

    def test_entity_type_filter_dashboard_excludes_standalone_computations(self):
        # given
        start_ms = int(time.time() * 1000)
        self.kawa.sheet(sheet_id=self.sheet_id).view_id(self.standalone_layout_id).compute()
        self.kawa.sheet(sheet_id=self.sheet_id).view_id(self.dashboard_layout_id).compute()

        # when
        r = self.kawa.reporting().generate_computation_views_report(from_ms=start_ms, entity_type='dashboard')

        # then
        self.assertTrue((r['layout_id'] == self.dashboard_layout_id).any())
        self.assertFalse((r['layout_id'] == self.standalone_layout_id).any())

    def test_principal_id_filter_returns_only_that_users_computations(self):
        # given
        start_ms = int(time.time() * 1000)
        self.kawa.sheet(sheet_id=self.sheet_id).view_id(self.standalone_layout_id).compute()
        self.kawa_second_user.sheet(sheet_id=self.sheet_id).view_id(self.standalone_layout_id).compute()

        # when
        r = self.kawa.reporting().generate_computation_views_report(
            from_ms=start_ms,
            principal_id=self.admin_principal_id,
        )

        # then
        match = r[r['layout_id'] == self.standalone_layout_id]
        self.assertEqual(len(match), 1)
        self.assertEqual(match.iloc[0]['user_id'], self.admin_principal_id)

    def test_returns_dataframe_with_expected_columns(self):
        r = self.kawa.reporting().generate_computation_views_report()
        self.assertListEqual(list(r.columns), [
            'user_id',
            'user_email',
            'user_display_information',
            'layout_id',
            'layout_display_information',
            'dashboard_id',
            'dashboard_display_information',
            'application_id',
            'application_display_information',
            'timestamp',
        ])
