# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from datetime import datetime, timedelta, time

from odoo.addons.base.tests.common import HttpCaseWithUserDemo, HttpCaseWithUserPortal
from odoo.addons.base.tests.test_ir_cron import CronMixinCase
from odoo.addons.event.tests.common import EventCase
from odoo.addons.event_crm.tests.common import EventCrmCase
from odoo.addons.mail.tests.common import mail_new_test_user, MailCommon
from odoo.addons.sales_team.tests.common import TestSalesCommon
from odoo.addons.sms.tests.common import SMSCase
from odoo.addons.website.tests.test_website_visitor import MockVisitor


class TestEventFullCommon(EventCrmCase, TestSalesCommon, MockVisitor):

    @classmethod
    def setUpClass(cls):
        super(TestEventFullCommon, cls).setUpClass()

        # Context data: dates
        # ------------------------------------------------------------

        # Mock dates to have reproducible computed fields based on time
        cls.reference_now = datetime(2021, 12, 1, 10, 0, 0)
        cls.reference_today = datetime(2021, 12, 1)

        # Users and contacts
        # ------------------------------------------------------------

        cls.admin_user = cls.env.ref('base.user_admin')
        cls.admin_user.write({
            'country_id': cls.env.ref('base.be').id,
            'login': 'admin',
            'notification_type': 'inbox',
        })
        cls.company_admin = cls.admin_user.company_id
        # set country in order to format Belgian numbers
        cls.company_admin.write({
            'country_id': cls.env.ref('base.be').id,
            'email': 'info@yourcompany.com',
        })
        cls.event_user = mail_new_test_user(
            cls.env,
            company_id=cls.company_admin.id,
            company_ids=[(4, cls.company_admin.id)],
            country_id=cls.env.ref('base.be').id,
            groups='base.group_user,base.group_partner_manager,event.group_event_user',
            email='e.e@example.com',
            login='event_user',
            name='Ernest Employee',
            notification_type='inbox',
            signature='--\nErnest',
        )

        cls.customer = cls.env['res.partner'].create({
            'country_id': cls.env.ref('base.be').id,
            'email': 'customer.test@example.com',
            'name': 'Test Customer',
            'mobile': '0456123456',
            'phone': '0456123456',
        })
        # make a SO for a customer, selling some tickets
        cls.customer_so = cls.env['sale.order'].with_user(cls.user_sales_salesman).create({
            'partner_id': cls.event_customer.id,
        })

        # Side records for event main records
        # ------------------------------------------------------------

        cls.ticket_product = cls.env['product.product'].create({
            'description_sale': 'Ticket Product Description',
            'type': 'service',
            'service_tracking': 'event',
            'list_price': 10,
            'name': 'Test Registration Product',
            'standard_price': 30.0,
        })
        cls.booth_product = cls.env['product.product'].create({
            'description_sale': 'Booth Product Description',
            'type': 'service',
            'service_tracking': 'event_booth',
            'list_price': 20,
            'name': 'Test Booth Product',
            'standard_price': 60.0,
        })

        cls.tag_categories = cls.env['event.tag.category'].create([
            {'is_published': True, 'name': 'Published Category'},
            {'is_published': False, 'name': 'Unpublished Category'},
        ])
        cls.tags = cls.env['event.tag'].create([
            {'category_id': cls.tag_categories[0].id, 'name': 'PubTag1'},
            {'category_id': cls.tag_categories[0].id, 'color': 0, 'name': 'PubTag2'},
            {'category_id': cls.tag_categories[1].id, 'name': 'UnpubTag1'},
        ])

        cls.event_booth_categories = cls.env['event.booth.category'].create([
            {'description': '<p>Standard</p>',
             'name': 'Standard',
             'product_id': cls.booth_product.id,
            },
            {'description': '<p>Premium</p>',
             'name': 'Premium',
             'product_id': cls.booth_product.id,
             'price': 90,
            }
        ])

        cls.sponsor_types = cls.env['event.sponsor.type'].create([
            {'name': 'GigaTop',
             'sequence': 1,
            }
        ])
        cls.sponsor_partners = cls.env['res.partner'].create([
            {'country_id': cls.env.ref('base.be').id,
             'email': 'event.sponsor@example.com',
             'name': 'EventSponsor',
             'phone': '04856112233',
            }
        ])

        # Event type
        # ------------------------------------------------------------
        test_registration_report = cls.env.ref('test_event_full.event_registration_report_test')
        subscription_template = cls.env.ref('event.event_subscription')
        subscription_template.write({'report_template_ids': [(6, 0, test_registration_report.ids)]})
        cls.test_event_type = cls.env['event.type'].create({
            'default_timezone': 'Europe/Paris',
            'event_type_booth_ids': [
                (0, 0, {'booth_category_id': cls.event_booth_categories[0].id,
                        'name': 'Standard Booth',
                       }
                ),
                (0, 0, {'booth_category_id': cls.event_booth_categories[0].id,
                        'name': 'Standard Booth 2',
                       }
                ),
                (0, 0, {'booth_category_id': cls.event_booth_categories[1].id,
                        'name': 'Premium Booth',
                       }
                ),
                (0, 0, {'booth_category_id': cls.event_booth_categories[1].id,
                        'name': 'Premium Booth 2',
                       }
                ),
            ],
            'event_type_mail_ids': [
                (0, 0, {'interval_unit': 'now',  # right at subscription
                        'interval_type': 'after_sub',
                        'template_ref': 'mail.template,%i' % subscription_template.id,
                       }
                ),
                (0, 0, {'interval_nbr': 1,  # 1 days before event
                        'interval_unit': 'days',
                        'interval_type': 'before_event',
                        'template_ref': 'mail.template,%i' % cls.env['ir.model.data']._xmlid_to_res_id('event.event_reminder'),
                       }
                ),
                (0, 0, {'interval_nbr': 1,  # 1 days after event
                        'interval_unit': 'days',
                        'interval_type': 'after_event',
                        'template_ref': 'sms.template,%i' % cls.env['ir.model.data']._xmlid_to_res_id('event_sms.sms_template_data_event_reminder'),
                       }
                ),
            ],
            'event_type_ticket_ids': [
                (0, 0, {'description': 'Ticket1 Description',
                        'name': 'Ticket1',
                        'product_id': cls.ticket_product.id,
                        'seats_max': 10,
                       }
                ),
                (0, 0, {'description': 'Ticket2 Description',
                        'name': 'Ticket2',
                        'product_id': cls.ticket_product.id,
                        'price': 45,
                       }
                )
            ],
            'has_seats_limitation': True,
            'name': 'Test Type',
            'note': '<p>Template note</p>',
            'question_ids': [
                (0, 0, {'answer_ids':
                        [(0, 0, {'name': 'Q1-Answer1'}),
                         (0, 0, {'name': 'Q1-Answer2'}),
                        ],
                        'question_type': 'simple_choice',
                        'once_per_order': False,
                        'title': 'Question1',
                       }
                ),
                (0, 0, {'answer_ids':
                        [(0, 0, {'name': 'Q2-Answer1'}),
                         (0, 0, {'name': 'Q2-Answer2'}),
                        ],
                        'question_type': 'simple_choice',
                        'once_per_order': False,
                        'title': 'Question2',
                       }
                ),
                (0, 0, {'question_type': 'text_box',
                        'once_per_order': True,
                        'title': 'Question3',
                       }
                ),
            ],
            'seats_max': 30,
            'tag_ids': [(4, tag.id) for tag in cls.tags],
            'ticket_instructions': '<p>Ticket Instructions</p>',
            'website_menu': True,
        })

        # Stages
        cls.stage_def = cls.env['event.stage'].create({
            'name': 'First Stage',
            'sequence': 0,
        })

        # Event data
        # ------------------------------------------------------------

        cls.event_base_vals = {
            'name': 'Test Event',
            'date_begin': cls.reference_now + timedelta(days=1),
            'date_end': cls.reference_now + timedelta(days=5),
            'is_published': True,
        }

        with cls.mock_datetime_and_now(cls, cls.reference_now):
            cls.test_event = cls.env['event.event'].create({
                'name': 'Test Event',
                'date_begin': datetime.now() + timedelta(days=1),
                'date_end': datetime.now() + timedelta(days=5),
                'date_tz': 'Europe/Brussels',
                'event_type_id': cls.test_event_type.id,
                'is_published': True,
            })
        # update post-synchronize data
        ticket_1 = cls.test_event.event_ticket_ids.filtered(lambda t: t.name == 'Ticket1')
        ticket_2 = cls.test_event.event_ticket_ids.filtered(lambda t: t.name == 'Ticket2')
        ticket_1.start_sale_datetime = cls.reference_now + timedelta(hours=1)
        ticket_2.start_sale_datetime = cls.reference_now + timedelta(hours=2)

        # Website data
        # ------------------------------------------------------------

        cls.website = cls.env['website'].search([
            ('company_id', '=', cls.company_admin.id)
        ], limit=1)

        cls.customer_data = [
            {'email': f'customer.email.{idx:02d}@test.example.com',
             'name': f'My Customer {idx:02d}',
             'partner_id': False,
             'phone': f'04560000{idx:02d}',
            } for idx in range(0, 10)
        ]
        cls.website_customer_data = [
            {'email': f'website.email.{idx:02d}@test.example.com',
             'name': f'My Customer {idx:02d}',
             'partner_id': cls.env.ref('base.public_partner').id,
             'phone': f'04560000{idx:02d}',
             'registration_answer_ids': [
                (0, 0, {
                    'question_id': cls.test_event.question_ids[0].id,
                    'value_answer_id': cls.test_event.question_ids[0].answer_ids[(idx % 2)].id,
                }), (0, 0, {
                    'question_id': cls.test_event.question_ids[1].id,
                    'value_answer_id': cls.test_event.question_ids[1].answer_ids[(idx % 2)].id,
                }), (0, 0, {
                    'question_id': cls.test_event.question_ids[2].id,
                    'value_text_box': f'CustomerAnswer{idx}',
                })
             ],
            } for idx in range(0, 10)
        ]
        cls.partners = cls.env['res.partner'].create([
            {'email': f'partner.email.{idx:02d}@test.example.com',
             'name': f'PartnerCustomer {idx:02d}',
             'mobile': f'04569999{idx:02d}',
             'phone': f'04560000{idx:02d}',
            } for idx in range(0, 10)
        ])

    def assertLeadConvertion(self, rule, registrations, partner=None, **expected):
        super(TestEventFullCommon, self).assertLeadConvertion(rule, registrations, partner=partner, **expected)
        lead = self.env['crm.lead'].sudo().search([
            ('registration_ids', 'in', registrations.ids),
            ('event_lead_rule_id', '=', rule.id)
        ])

        for registration in registrations:
            if not registration.registration_answer_ids:
                continue
            for answer in registration.registration_answer_ids:
                self.assertIn(answer.question_id.title, lead.description)
                if answer.question_type == 'simple_choice':
                    self.assertIn(answer.value_answer_id.name, lead.description)
                else:
                    self.assertIn(answer.value_text_box, lead.description)  # better: check multi line


class TestEventMailCommon(EventCase, SMSCase, MailCommon, CronMixinCase):

    @classmethod
    def setUpClass(cls):
        super().setUpClass()

        cls.event_cron_id = cls.env.ref('event.event_mail_scheduler')
        # deactivate other schedulers to avoid messing with crons
        cls.env['event.mail'].search([]).unlink()
        # consider asynchronous sending as default sending
        cls.env["ir.config_parameter"].set_param("event.event_mail_async", False)

        cls.env.company.write({
            'email': 'info@yourcompany.example.com',
            'name': 'YourCompany',
        })

        # prepare SMS templates
        cls.sms_template_sub = cls.env['sms.template'].create({
            'name': 'Test SMS Subscription',
            'model_id': cls.env.ref('event.model_event_registration').id,
            'body': '{{ object.event_id.organizer_id.name }} registration confirmation.',
            'lang': '{{ object.partner_id.lang }}'
        })
        cls.sms_template_rem = cls.env['sms.template'].create({
            'name': 'Test SMS Reminder',
            'model_id': cls.env.ref('event.model_event_registration').id,
            'body': '{{ object.event_id.organizer_id.name }} reminder',
            'lang': '{{ object.partner_id.lang }}'
        })

        # freeze some datetimes, and ensure more than 1D+1H before event starts
        # to ease time-based scheduler check
        # Since `now` is used to set the `create_date` of an event and create_date
        # has often microseconds, we set it to ensure that the scheduler we still be
        # launched if scheduled_date == create_date - microseconds
        cls.reference_now = datetime(2021, 3, 20, 14, 30, 15, 123456)
        cls.event_date_begin = datetime(2021, 3, 25, 8, 0, 0)
        cls.event_date_end = datetime(2021, 3, 28, 18, 0, 0)

        cls._setup_test_reports()
        with cls.mock_datetime_and_now(cls, cls.reference_now):
            cls.test_event = cls.env['event.event'].create({
                'name': 'TestEventMail',
                'user_id': cls.user_eventmanager.id,
                'date_begin': cls.event_date_begin,
                'date_end': cls.event_date_end,
                'event_mail_ids': [
                    (0, 0, {  # right at subscription: mail
                        'interval_unit': 'now',
                        'interval_type': 'after_sub',
                        'notification_type': 'mail',
                        'template_ref': f'mail.template,{cls.template_subscription.id}',
                    }),
                    (0, 0, {  # right at subscription: sms
                        'interval_unit': 'now',
                        'interval_type': 'after_sub',
                        'notification_type': 'sms',
                        'template_ref': f'sms.template,{cls.sms_template_sub.id}',
                    }),
                    (0, 0, {  # 3 days before event: mail
                        'interval_nbr': 3,
                        'interval_unit': 'days',
                        'interval_type': 'before_event',
                        'notification_type': 'mail',
                        'template_ref': f'mail.template,{cls.template_reminder.id}',
                    }),
                    (0, 0, {  # 3 days before event: SMS
                        'interval_nbr': 3,
                        'interval_unit': 'days',
                        'interval_type': 'before_event',
                        'notification_type': 'sms',
                        'template_ref': f'sms.template,{cls.sms_template_rem.id}',
                    }),
                    (0, 0, {  # 1h after event: mail
                        'interval_nbr': 1,
                        'interval_unit': 'hours',
                        'interval_type': 'after_event',
                        'notification_type': 'mail',
                        'template_ref': f'mail.template,{cls.template_reminder.id}',
                    }),
                    (0, 0, {  # 1h after event: SMS
                        'interval_nbr': 1,
                        'interval_unit': 'hours',
                        'interval_type': 'after_event',
                        'notification_type': 'sms',
                        'template_ref': f'sms.template,{cls.sms_template_rem.id}',
                    }),
                ],
            })


class TestWEventCommon(HttpCaseWithUserDemo, HttpCaseWithUserPortal, MockVisitor):

    def setUp(self):
        super(TestWEventCommon, self).setUp()

        # Context data: dates
        # ------------------------------------------------------------

        # Mock dates to have reproducible computed fields based on time
        self.reference_now = datetime(2021, 12, 1, 10, 0, 0)
        self.reference_today = datetime(2021, 12, 1)

        self.event_product = self.env['product.product'].create({
            'name': 'Test Event Registration',
            'default_code': 'EVENT_REG',
            'description_sale': 'Mighty Description',
            'list_price': 10,
            'standard_price': 30.0,
            'type': 'service',
            'service_tracking': 'event',
        })

        self.event_tag_category_1 = self.env['event.tag.category'].create({
            'name': 'Type',
            'sequence': 2,
        })
        self.event_tag_category_1_tag_1 = self.env['event.tag'].create({
            'name': 'Online',
            'sequence': 10,
            'category_id': self.event_tag_category_1.id,
            'color': 8,
        })
        self.env['event.event'].search(
            [('name', 'like', 'Online Reveal')]
        ).write(
            {'name': 'Do not click on me'}
        )
        self.event = self.env['event.event'].create({
            'name': 'Online Reveal TestEvent',
            'stage_id': self.env.ref('event.event_stage_booked').id,
            'address_id': False,
            'user_id': self.user_demo.id,
            'tag_ids': [(4, self.event_tag_category_1_tag_1.id)],
            # event if 8-18 in Europe/Brussels (DST) (first day: begins at 7, last day: ends at 17)
            'date_tz': 'Europe/Brussels',
            'date_begin': datetime.combine(self.reference_now, time(5, 0)) - timedelta(days=1),
            'date_end': datetime.combine(self.reference_now, time(15, 0)) + timedelta(days=1),
            # ticket informations
            'event_ticket_ids': [
                (0, 0, {
                    'name': 'Standard',
                    'product_id': self.event_product.id,
                    'price': 0,
                }), (0, 0, {
                    'name': 'VIP',
                    'product_id': self.event_product.id,
                    'seats_max': 10,
                })
            ],
            # activate menus
            'is_published': True,
            'website_menu': True,
            'website_track': True,
            'website_track_proposal': True,
            'exhibitor_menu': True,
            'community_menu': True,
        })

        self.event_customer = self.env['res.partner'].create({
            'name': 'Constantin Customer',
            'email': 'constantin@test.example.com',
            'country_id': self.env.ref('base.be').id,
            'phone': '0485112233',
            'mobile': False,
        })
        self.event_speaker = self.env['res.partner'].create({
            'name': 'Brandon Freeman',
            'email': 'brandon.freeman55@example.com',
            'phone': '(355)-687-3262',
        })

        # ------------------------------------------------------------
        # QUESTIONS
        # ------------------------------------------------------------

        self.event_question_1 = self.env['event.question'].create({
            'title': 'Which field are you working in',
            'question_type': 'simple_choice',
            'event_id': self.event.id,
            'once_per_order': False,
            'answer_ids': [
                (0, 0, {'name': 'Consumers'}),
                (0, 0, {'name': 'Sales'}),
                (0, 0, {'name': 'Research'}),
            ],
        })
        self.event_question_2 = self.env['event.question'].create({
            'title': 'How did you hear about us ?',
            'question_type': 'text_box',
            'event_id': self.event.id,
            'once_per_order': True,
        })

        # ------------------------------------------------------------
        # TRACKS
        # ------------------------------------------------------------

        self.track_0 = self.env['event.track'].create({
            'name': 'What This Event Is All About',
            'event_id': self.event.id,
            'stage_id': self.env.ref('website_event_track.event_track_stage3').id,
            'date': self.reference_now + timedelta(hours=1),
            'duration': 2,
            'is_published': True,
            'wishlisted_by_default': True,
            'user_id': self.user_admin.id,
            'partner_id': self.event_speaker.id,
        })
        self.track_1 = self.env['event.track'].create({
            'name': 'Live Testimonial',
            'event_id': self.event.id,
            'stage_id': self.env.ref('website_event_track.event_track_stage3').id,
            'date': self.reference_now - timedelta(minutes=30),
            'duration': 0.75,
            'is_published': True,
            'user_id': self.user_admin.id,
            'partner_id': self.event_speaker.id,
        })
        self.track_2 = self.env['event.track'].create({
            'name': 'Our Last Day Together!',
            'event_id': self.event.id,
            'stage_id': self.env.ref('website_event_track.event_track_stage3').id,
            'date': self.reference_now + timedelta(days=1),
            'duration': 0.75,
            'is_published': True,
            'user_id': self.user_admin.id,
            'partner_id': self.event_speaker.id,
        })

        # ------------------------------------------------------------
        # MEETING ROOMS
        # ----------------------------------------------------------

        self.env['event.meeting.room'].create({
            'name': 'Best wood for furniture',
            'summary': 'Let\'s talk about wood types for furniture',
            'target_audience': 'wood expert(s)',
            'is_pinned': True,
            'website_published': True,
            'event_id': self.event.id,
            'room_lang_id': self.env.ref('base.lang_en').id,
            'room_max_capacity': '12',
            'room_participant_count': 9,
        })

        self.env.flush_all()
