from datetime import datetime, timedelta
from dostadmin import app, db, db_model, app_logger
from dostadmin.services.scheduling.pre_calculated_campaign_service import (
    PreCalculatedCampaignService,
)
from dostadmin.services.scheduling.call_attempt_service import CallAttemptService
from dostadmin.services.scheduling.campaign_creation_service import (
    CampaignCreationService,
)
from dostadmin.services.content.content_service import ContentService
from dostadmin.services.experience.experience_service import ExperienceService
from utils.helpers import helpers
from utils.helpers.helpers import get_current_utc_time
import traceback


class MissedCallService:
    def update_missed_call_status(
        self, cursor, missed_call_id, status, new_campaign_id
    ):
        if new_campaign_id != -1:
            cursor.execute(
                f"UPDATE engagement SET missed_call_status='{status}', "
                f"updated_on='{get_current_utc_time()}', "
                f"campaign_id={new_campaign_id} WHERE id='{missed_call_id}'"
            )
        else:
            cursor.execute(
                f"UPDATE engagement SET missed_call_status='{status}', "
                f"updated_on='{get_current_utc_time().strftime('%Y-%m-%d %H:%M:%S.%f')}' "
                f"WHERE id='{missed_call_id}'"
            )

    def get_intro_content_for_all(self, cursor):
        SQL = "SELECT phone, content_id FROM providernumber;"
        cursor.execute(SQL)
        all_intros = cursor.fetchall()

        intro_content_obj = {}
        for intro in all_intros:
            intro_content_obj[intro[0]] = intro[1]

        return intro_content_obj

    def handle_missed_call(self, data):
        try:
            call_sid = data.get("CallSid")
            user_number = data.get("From")

            if self.has_duplicate_missedcall_log(call_sid):
                app_logger.info(
                    f"Found duplicate missed call log for phone: {user_number} and with id: {call_sid}"
                )
                return

            engagement_data = self.prepare_engagement_dict(data)
            missed_call_log = self.create_missed_call_log(engagement_data)
            provider_number = data.get("To")

            experience = ExperienceService().check_for_existing_experience(user_number)

            if not experience:
                app_logger.info(
                    f"First time missed call from phone number {user_number} with call sid {call_sid}"
                )
                (
                    experience,
                    campaign_id,
                ) = self.handle_experience_creation_for_new_user(
                    user_number, provider_number
                )
                missed_call_log.experience_id = experience.id
                missed_call_log.missed_call_status = (
                    db_model.MissedCallLog.MissedCallStatus.SCHEDULED
                )
                missed_call_log.campaign_id = campaign_id
                db.session.commit()

                return

            if experience.status == db_model.Experience.Status.DND_WAIT:
                campaign = self.handle_missed_call_for_DND_users(experience)
                if campaign:
                    missed_call_log.missed_call_status = (
                        db_model.MissedCallLog.MissedCallStatus.SCHEDULED
                    )
                    missed_call_log.campaign_id = campaign.id
                    db.session.commit()

                    return

            if (
                experience.provider_number[-10:]
                in app.config["TAF_EXPERIMENT_PROVIDER_NUMBERS"]
            ):
                is_missed_call_ignored = self.handle_taf_user_missed_call(
                    experience, missed_call_log
                )

                if is_missed_call_ignored:
                    return

            previous_missed_call_log = (
                db_model.MissedCallLog.get_latest_missedcalllog_for_experience(
                    experience
                )
            )

            previous_campaign = (
                db_model.Campaign.query.get_campaign_by_id(
                    previous_missed_call_log.campaign_id
                )
                if previous_missed_call_log
                else None
            )

            if (
                previous_campaign
                and previous_campaign.status == db_model.Campaign.Status.SCHEDULED
            ):
                app_logger.info(
                    f"Previous missed call is not yet processed for number {user_number}. Ignoring this missed call."
                )
                missed_call_log.missed_call_status = (
                    db_model.MissedCallLog.MissedCallStatus.IGNORED
                )
                db.session.commit()
                return

            self.create_campaign_for_existing_users(experience, missed_call_log)
        except Exception as e:
            app_logger.error(f"Missed Call Service: Exception occurred: {e}")
            app_logger.debug(traceback.format_exc())

    def handle_taf_user_missed_call(self, experience, missed_call_log):
        if (
            experience.status == db_model.Experience.Status.PAUSED
            and datetime.date(experience.created_on)
            != helpers.get_current_isttime().date()
        ) or experience.status == db_model.Experience.Status.COMPLETED:
            missed_call_log.missed_call_status = (
                db_model.MissedCallLog.MissedCallStatus.IGNORED
            )
            db.session.commit()

            return True

        return False

    def handle_missed_call_for_DND_users(self, experience):
        experience_id = experience.id
        provider_number = experience.provider_number
        program_details = db_model.Program.query.get_program_details(
            experience.program_id
        )
        program_status = program_details.status
        pre_calculated_user_campaign_data = (
            db_model.PreCalculatedUserCampaignData.query.get_data_by_experience_id(
                experience_id
            )
        )
        is_last_call_six_month_ago = self.is_last_call_six_month_ago(
            pre_calculated_user_campaign_data
        )

        if (
            program_status == db_model.Program.Status.INACTIVE
            or (
                pre_calculated_user_campaign_data.today_content_id is None
                and pre_calculated_user_campaign_data.previous_content_id is None
            )
            or is_last_call_six_month_ago
        ):
            try:
                new_experience = (
                    ExperienceService().create_new_experience_for_DND_users(experience)
                )
                pre_calculated_campaign_data = (
                    PreCalculatedCampaignService().add_new_experience(new_experience.id)
                )
                campaign = self.get_provider_and_create_campaign(
                    provider_number, new_experience, pre_calculated_campaign_data
                )

                return campaign
            except Exception as e:
                app_logger.error(
                    f"Missed Call Service: Error while creating new experience for DND experience with id {experience_id}. Error Message {e}"
                )
                return None
        else:
            campaign = self.handle_campaign_creation_for_dnd_user(
                experience, pre_calculated_user_campaign_data
            )

            return campaign

    def is_last_call_six_month_ago(self, pre_calculated_user_campaign_data):
        last_call_deploy_time = self.get_last_call_deploy_time(
            pre_calculated_user_campaign_data
        )
        if last_call_deploy_time:
            six_month_ago = datetime.now() - timedelta(days=6 * 30)
            return last_call_deploy_time.date() < six_month_ago.date()
        return True

    def get_last_call_deploy_time(self, pre_calculated_user_campaign_data):
        previous_regular_call = (
            pre_calculated_user_campaign_data.previous_regular_call_deploy_time
        )
        previous_missed_call = (
            pre_calculated_user_campaign_data.previous_missed_call_deploy_time
        )

        if previous_regular_call is not None and previous_missed_call is not None:
            return max(previous_regular_call, previous_missed_call)

        return previous_regular_call or previous_missed_call

    def get_provider_and_create_campaign(
        self, provider_number, new_experience, pre_calculated_campaign_data
    ):
        callback_content_id = ContentService().get_default_intro_call_content(
            provider_number
        )
        callback_programseq_id = app.config["MISSED_CALL_CONFIRMATION_CALL_PSEQ_ID"]

        provider = db_model.ProviderNumber.query.find_provider_number_with_phone(
            provider_number
        )
        if provider:
            callback_content_id = provider.content_id
            callback_programseq_id = (
                db_model.Programseq.query.get_programseq_id_with_content_id(
                    callback_content_id
                )
            )
        campaign = self.create_confirmation_call(
            new_experience,
            pre_calculated_campaign_data,
            callback_content_id,
            callback_programseq_id,
            db_model.Campaign.ScheduledBy.CRON_MISSED_CALL,
        )

        return campaign

    def handle_experience_creation_for_new_user(self, user_number, provider_number):
        try:
            program_order = {}
            registration_data = {}
            language_id = None
            partner_id = db_model.Partner.query.get_id_with_name("callin")
            user_type_id = db_model.UserType.query.get_user_type_id_by_name(
                db_model.UserType.Type.PARENT
            )
            provider = db_model.ProviderNumber.query.find_provider_number_with_phone(
                provider_number
            )
            if provider:
                partner_id = provider.partner_id
                language_id = provider.language_id

            registration_data["partner_id"] = partner_id
            partner = db_model.Partner.query.get_by_id(partner_id)
            if partner:
                registration_data["state"] = partner.state
                registration_data["district"] = partner.district
                registration_data["block"] = partner.block

            if not partner:
                app_logger.error(
                    f"Missedcall Service: Partner not found for the id {partner_id}."
                )

            app_logger.info(
                f"Creating new user entry for {user_number} with {provider_number} as provider number."
            )
            user = db_model.User(
                name="fnu",
                partner_id=partner_id,
                program_order=program_order,
                user_type_id=user_type_id,
                signup_status=db_model.user.User.Status.INCOMPLETE,
            )
            db.session.add(user)
            db.session.commit()

            experience = self.start_experience(
                user.id, user_number, provider_number, registration_data, language_id
            )

            pre_calculated_campaign_data = (
                PreCalculatedCampaignService().add_new_experience(experience.id)
            )

            campaign = self.get_provider_and_create_campaign(
                provider_number, experience, pre_calculated_campaign_data
            )

            if not campaign:
                app_logger.error(
                    f"Missed Call Service: Intro call not created for phone number {user_number}"
                )
                return experience, None

            CallAttemptService().attempt_call(
                experience, campaign, pre_calculated_campaign_data, True
            )

            return experience, campaign.id
        except Exception as e:
            app_logger.error(
                f"Error on function handle_experience_creation_for_new_user: {e}"
            )

    def start_experience(
        self, user_id, phone, provider_number, registration_data, language_id=None
    ):
        try:
            today_date = helpers.get_current_isttime().date()
            next_day = today_date + timedelta(days=1)

            if provider_number == app.config["ASSAM_PROVIDER_NUMBER"]:
                program_id = (
                    db_model.Program.query.find_program_id_with_name(
                        app.config["ASSAM_DEFAULT_PROGRAM_NAME"]
                    ),
                )
            elif provider_number[-10:] in app.config["TAF_EXPERIMENT_PROVIDER_NUMBERS"]:
                program_id = (
                    db_model.Program.query.find_program_id_with_name(
                        app.config["EXPERIMENT_DEFAULT_PROGRAM_NAME"]
                    ),
                )
            elif provider_number[-10:] in app.config["BIHAR_PROVIDER_NUMBERS"]:
                program_id = (
                    db_model.Program.query.find_program_id_with_name(
                        app.config["BIHAR_DEFAULT_PROGRAM_NAME"]
                    ),
                )
            elif provider_number[-10:] in app.config["MP_PROVIDER_NUMBERS"]:
                program_id = (
                    db_model.Program.query.find_program_id_with_name(
                        app.config["MP_DEFAULT_PROGRAM_NAME"]
                    ),
                )
            else:
                program_id = (
                    db_model.Program.query.find_program_id_with_name(
                        app.config["DEFAULT_MISSED_CALL_PROGRAM_NAME"]
                    ),
                )

            app_logger.info(
                f"Starting new experience for {phone} with {provider_number} as provider number."
            )
            new_experience = db_model.Experience(
                user_id=user_id,
                status=db_model.Experience.Status.PENDING,
                phone=phone[-10:],
                language_id=language_id
                if language_id
                else db_model.Language.query.find_language_id_with_name(),
                timecategory_id=db_model.Timecategory.query.find_timecategory_id_with_name(
                    app.config["DEFAULT_MISSED_CALL_TIME_CATEGORY"]
                ),
                program_id=program_id,
                start_date=datetime.strftime(next_day, "%Y-%m-%d"),
                provider_number=provider_number,
                type=db_model.Experience.Type.SELFPACEDPC,
            )

            app_logger.info(
                f"Creating new registration for {phone} with {provider_number} as provider number."
            )
            registration = db_model.Registration(
                user_id=user_id,
                phone=phone[-10:],
                provider_number=provider_number,
                partner_id=registration_data.get("partner_id"),
                program_id=new_experience.program_id,
                time_category_id=new_experience.timecategory_id,
                signup_status=db_model.user.User.Status.INCOMPLETE,
                district=registration_data.get("district"),
                state=registration_data.get("state"),
                block=registration_data.get("block"),
                onboarding_source=db_model.Registration.OnboardingSource.MISSED_CALL_REGISTERED,
            )
            db.session.add(registration)
            db.session.add(new_experience)
            db.session.commit()
            return new_experience
        except Exception as e:
            app_logger.error(f"Error on function start_experience: {e}")

    def create_confirmation_call(
        self,
        experience,
        pre_calculated_campaign_data,
        content_id=app.config["CONFIRMATION_CALL_CONTENT_ID"],
        programseq_id=app.config["CONFIRMATION_CALL_PSEQ_ID"],
        scheduled_by=db_model.Campaign.ScheduledBy.CRON_REGULAR,
    ):
        language_id = experience.language_id
        content_version = db_model.content_version.ContentVersion.query.get_content_version_by_content_and_language_id(
            content_id, language_id
        )
        app_logger.info(
            "Creating first confirmation call for user with phone %s", experience.phone
        )
        campaign = db_model.Campaign(
            name="W0D0_" + str(experience.user_id),
            content_id=content_id,
            content_version_id=content_version.id,
            user_number=experience.phone,
            deploy_datetime=helpers.get_current_isttime() + timedelta(seconds=2),
            status=db_model.Campaign.Status.SCHEDULED,
            experience_id=experience.id,
            scheduled_by=scheduled_by,
            user_id=experience.user_id,
            provider_number=experience.provider_number,
            programseq_id=programseq_id,
            timecategory_id=experience.timecategory_id,
        )
        db.session.add(campaign)
        db.session.commit()

        pre_calculated_campaign_data.call_details_for_date = (
            helpers.get_current_isttime().date()
        )
        pre_calculated_campaign_data.previous_missed_call_campaign_id = campaign.id
        pre_calculated_campaign_data.previous_missed_call_campaign_status = (
            campaign.status
        )
        pre_calculated_campaign_data.today_content_id = campaign.content_id
        pre_calculated_campaign_data.previous_content_id = campaign.content_id
        pre_calculated_campaign_data.today_content_version_id = (
            campaign.content_version_id
        )
        pre_calculated_campaign_data.previous_content_version_id = (
            campaign.content_version_id
        )
        pre_calculated_campaign_data.previous_campaign_name = campaign.name
        pre_calculated_campaign_data.previous_missed_call_deploy_time = (
            campaign.deploy_datetime
        )

        campaign_data = {
            "campaign_id": campaign.id,
            "campaign_name": campaign.name,
            "experience_id": campaign.experience_id,
            "deploy_datetime": campaign.deploy_datetime,
            "content_id": campaign.content_id,
            "content_version_id": campaign.content_version_id,
            "scheduled_by": campaign.scheduled_by,
        }
        PreCalculatedCampaignService().update_pre_calculated_user_campaign_data(
            campaign_data
        )

        return campaign

    def create_campaign_for_existing_users(self, experience, missed_call_log):
        pre_calculated_user_campaign_data = (
            db_model.PreCalculatedUserCampaignData.query.get_data_by_experience_id(
                experience.id
            )
        )

        if not pre_calculated_user_campaign_data:
            app_logger.error(
                f"PreCalculated data not found for existing user {missed_call_log.phone} and experience id {experience.id}"
            )
            missed_call_log.missed_call_status = (
                db_model.MissedCallLog.MissedCallStatus.IGNORED
            )
            db.session.commit()
            return None

        campaign = None

        if experience.status in [
            db_model.Experience.Status.ACTIVE,
            db_model.Experience.Status.PENDING,
        ]:
            campaign = self.get_campaign_for_active_experience(
                experience, pre_calculated_user_campaign_data
            )
        elif experience.status == db_model.Experience.Status.UNSUBSCRIBE:
            campaign = self.handle_campaign_creation_for_unsubscribed_user(experience)
        elif experience.status == db_model.Experience.Status.PAUSED:
            campaign = self.handle_campaign_creation_for_paused_user(
                experience, pre_calculated_user_campaign_data
            )
        elif experience.status == db_model.Experience.Status.COMPLETED:
            campaign = self.handle_campaign_creation_for_completed_user(experience)
        elif experience.status == db_model.Experience.Status.CHURNED:
            campaign = self.handle_campaign_creation_for_churned_user(experience)

        missed_call_log.experience_id = experience.id

        if campaign is None:
            app_logger.warning(
                f"CampaignCreationService: No campaign was scheduled for phone number {experience.phone} and missed call id {missed_call_log.id}"
            )
            missed_call_log.missed_call_status = (
                db_model.MissedCallLog.MissedCallStatus.IGNORED
            )
            db.session.commit()

            return missed_call_log

        CallAttemptService().attempt_call(
            experience, campaign, pre_calculated_user_campaign_data, True
        )
        missed_call_log.campaign_id = campaign.id
        missed_call_log.missed_call_status = (
            db_model.MissedCallLog.MissedCallStatus.SCHEDULED
        )

        if experience.status not in [
            db_model.Experience.Status.UNSUBSCRIBE,
            db_model.Experience.Status.CHURNED,
            db_model.Experience.Status.COMPLETED,
        ]:
            pre_calculated_user_campaign_data.previous_campaign_name = campaign.name
            pre_calculated_user_campaign_data.previous_content_id = campaign.content_id
            pre_calculated_user_campaign_data.previous_content_version_id = (
                campaign.content_version_id
            )
            pre_calculated_user_campaign_data.previous_missed_call_campaign_id = (
                campaign.id
            )
            pre_calculated_user_campaign_data.previous_missed_call_deploy_time = (
                campaign.deploy_datetime
            )
            pre_calculated_user_campaign_data.previous_missed_call_campaign_status = (
                campaign.status
            )

        db.session.commit()

        return missed_call_log

    def get_campaign_for_active_experience(
        self, experience, pre_calculated_user_campaign_data
    ):
        previous_call_data = PreCalculatedCampaignService().get_previous_campaign_data(
            pre_calculated_user_campaign_data, True, False
        )
        previous_deploy_time = previous_call_data.get("deploy_time")
        is_current_date_call = helpers.is_current_date_timestamp(previous_deploy_time)
        campaign_creation_service = CampaignCreationService()
        special_content_ids = campaign_creation_service.get_special_content_ids()
        content_id = pre_calculated_user_campaign_data.today_content_id
        previous_content_id = pre_calculated_user_campaign_data.previous_content_id

        if (
            previous_call_data.get("status") == db_model.Campaign.Status.SCHEDULED
            and is_current_date_call
        ):
            campaign = db_model.Campaign.query.get_campaign_by_id(
                previous_call_data.get("campaign_id")
            )
            campaign.scheduled_by = db_model.Campaign.ScheduledBy.CRON_MISSED_CALL
            campaign.deploy_datetime = helpers.get_current_isttime()
            pre_calculated_user_campaign_data.previous_missed_call_campaign_id = (
                previous_call_data.get("campaign_id")
            )
            pre_calculated_user_campaign_data.previous_missed_call_deploy_time = (
                campaign.deploy_datetime
            )
            pre_calculated_user_campaign_data.previous_missed_call_campaign_status = (
                campaign.status
            )
        else:
            previous_call_name = previous_call_data.get("campaign_name")

            if previous_call_name:
                new_campaign_name = campaign_creation_service.get_campaign_name(
                    previous_call_name
                )
            else:
                new_campaign_name = f"W1D1_{experience.user_id}"

            content_version = db_model.ContentVersion.query.get_content_version_by_content_and_language_id(
                content_id, experience.language_id
            )

            if (
                previous_call_data.get("status") == db_model.Campaign.Status.COMPLETED
                and content_id != previous_content_id
                and not is_current_date_call
            ):
                experience = db_model.Experience.query.get_by_id(
                    pre_calculated_user_campaign_data.experience_id
                )
                if content_id in special_content_ids:
                    new_campaign_name = (
                        campaign_creation_service.get_campaign_name_for_intro_calls(
                            previous_call_data.get("campaign_name"), experience.user_id
                        )
                    )
                else:
                    program_sequence = db_model.Programseq.query.get_program_seq_by_content_and_program(
                        experience.program_id, content_id
                    )
                    new_campaign_name = campaign_creation_service.get_campaign_name_from_program_sequence_and_user_id(
                        program_sequence, experience.user_id
                    )

            if not content_version:
                app_logger.error(
                    f"MissedCallService: While handling missed call for phone number {experience.phone}, the content version couldn't be found for content id {content_id} and language_id {experience.language_id}"
                )
                return None

            program_sequence = (
                db_model.Programseq.query.get_program_seq_by_content_and_program(
                    experience.program_id, content_id
                )
            )
            campaign = db_model.Campaign(
                name=new_campaign_name,
                deploy_datetime=helpers.get_current_isttime(),
                user_number=experience.phone,
                provider_number=experience.provider_number,
                scheduled_by=db_model.Campaign.ScheduledBy.CRON_MISSED_CALL,
                status=db_model.Campaign.Status.SCHEDULED,
                content_id=content_id,
                content_version_id=content_version.id,
                experience_id=experience.id,
                user_id=experience.user_id,
                timecategory_id=experience.timecategory_id,
                program_id=experience.program_id,
                programseq_id=program_sequence.id if program_sequence else None,
            )

            db.session.add(campaign)
            db.session.flush()

        return campaign

    def handle_campaign_creation_for_unsubscribed_user(self, experience):
        try:
            if experience.provider_number == app.config["ASSAM_PROVIDER_NUMBER"]:
                return None

            callback_content_id = app.config["UNSUBSCRIBE_CALLBACK_CONTENT_ID"]
            language_id = experience.language_id
            content_version = db_model.content_version.ContentVersion.query.get_content_version_by_content_and_language_id(
                callback_content_id, language_id
            )

            new_campaign = db_model.Campaign(
                name="RESUB_" + str(experience.user_id),
                content_id=callback_content_id,
                content_version_id=content_version.id,
                deploy_datetime=helpers.get_current_isttime(),
                status=db_model.Campaign.Status.SCHEDULED,
                experience_id=experience.id,
                scheduled_by=db_model.Campaign.ScheduledBy.CRON_MISSED_CALL,
                user_id=experience.user_id,
                provider_number=experience.provider_number,
                user_number=experience.phone,
                programseq_id=None,
                timecategory_id=experience.timecategory_id,
            )
            db.session.add(new_campaign)
            db.session.flush()

            return new_campaign
        except Exception as e:
            app_logger.error(
                f"Error occurred while creating campaign for unsubscribed user with number {experience.phone}. Error Message: {e}"
            )
            return None

    def handle_campaign_creation_for_churned_user(self, experience):
        try:
            callback_content_id = app.config["CHURNED_USER_CALLBACK_CONTENT_ID"]
            language_id = experience.language_id
            content_version = db_model.content_version.ContentVersion.query.get_content_version_by_content_and_language_id(
                callback_content_id, language_id
            )

            new_campaign = db_model.Campaign(
                name="RESUB_" + str(experience.user_id),
                content_id=callback_content_id,
                content_version_id=content_version.id,
                deploy_datetime=helpers.get_current_isttime(),
                status=db_model.Campaign.Status.SCHEDULED,
                experience_id=experience.id,
                scheduled_by=db_model.Campaign.ScheduledBy.CRON_MISSED_CALL,
                user_id=experience.user_id,
                provider_number=experience.provider_number,
                user_number=experience.phone,
                programseq_id=None,
                timecategory_id=experience.timecategory_id,
            )
            db.session.add(new_campaign)
            db.session.flush()

            return new_campaign
        except Exception as e:
            app_logger.error(
                f"Error occurred while creating campaign for churned user with number {experience.phone}. Error Message: {e}"
            )
            return None

    def handle_campaign_creation_for_completed_user(self, experience):
        try:
            if experience.provider_number == app.config["ASSAM_PROVIDER_NUMBER"]:
                return None
            content_id = app.config["COMPLETED_USER_PROGRAM_OPTIN_CONTENT_ID"]
            content_version = db_model.content_version.ContentVersion.query.get_content_version_by_content_and_language_id(
                content_id, experience.language_id
            )

            new_campaign = db_model.Campaign(
                name="ALUMNI_" + str(experience.user_id),
                content_id=content_id,
                content_version_id=content_version.id,
                deploy_datetime=helpers.get_current_isttime(),
                status=db_model.Campaign.Status.SCHEDULED,
                experience_id=experience.id,
                scheduled_by=db_model.Campaign.ScheduledBy.CRON_MISSED_CALL,
                user_id=experience.user_id,
                provider_number=experience.provider_number,
                user_number=experience.phone,
                programseq_id=None,
                timecategory_id=experience.timecategory_id,
            )
            db.session.add(new_campaign)
            db.session.flush()

            return new_campaign
        except Exception as e:
            app_logger.error(
                f"Error occurred while creating campaign for completed user with number {experience.phone}. Error Message: {e}"
            )
            return None

    def handle_campaign_creation_for_dnd_user(
        self, experience, pre_calculated_user_campaign_data
    ):
        try:
            experience.status = db_model.Experience.Status.ACTIVE
            pre_calculated_user_campaign_data.is_eligible_to_call = True
            db.session.commit()

            return None
        except Exception as e:
            app_logger.error(
                f"Error occurred while creating campaign for unsubscribed user with number {experience.phone}. Error Message: {e}"
            )
            return None

    def handle_campaign_creation_for_paused_user(
        self, experience, pre_calculated_user_campaign_data
    ):
        try:
            experience.status = db_model.Experience.Status.ACTIVE
            pre_calculated_user_campaign_data.is_eligible_to_call = True
            db.session.commit()

            return None
        except Exception as e:
            app_logger.error(
                f"Error occurred while creating campaign for unsubscribed user with number {experience.phone}. Error Message: {e}"
            )
            return None

    def create_missed_call_log(self, data):
        missed_call_log = db_model.MissedCallLog(
            exotelnumber=data.get("exotelnumber"),
            experience_id=data.get("experience_id"),
            phone=data.get("phone"),
            id=data.get("id"),
            start_time=data.get("start_time"),
            missed_call_status=data.get(
                "missed_call_status",
                db_model.MissedCallLog.MissedCallStatus.TO_SCHEDULE,
            ),
            campaign_id=data.get("campaign_id"),
        )
        db.session.add(missed_call_log)
        db.session.commit()

        return missed_call_log

    def prepare_engagement_dict(self, data):
        user_number = data.get("From")
        user_number = user_number[1:]
        engagement_data = {}
        engagement_data["id"] = data.get("CallSid")
        engagement_data["exotelnumber"] = data.get("To")
        engagement_data["phone"] = user_number
        engagement_data["start_time"] = (
            datetime.strptime(data["StartTime"], "%Y-%m-%d %H:%M:%S")
            if data.get("StartTime")
            else datetime.now()
        )
        engagement_data["campaign_id"] = data.get("campaign_id")
        return engagement_data

    def has_duplicate_missedcall_log(self, call_sid):
        if db_model.MissedCallLog.query.get_by_id(call_sid):
            return True
        return False
