# -*- coding: utf-8 -*-
import datetime

from django.conf import settings
from django.db import connections


def get_ro_connection():
    return connections[settings.DATABASE_ROLOCAL]


def get_rw_connection():
    return connections[settings.DATABASE_DEFAULT]


class DropNotifications:
    def __init__(self, last_day, limit):
        self.last_day = last_day
        self.limit = limit

    def execute_once(self):
        args = (self.last_day, self.limit)
        with get_rw_connection().cursor() as c:
            c.execute('''
                delete from surveyme_integration_hooksubscriptionnotification
                 where id in (
                    select t.id
                      from surveyme_integration_hooksubscriptionnotification t
                     where t.date_created < %s
                     limit %s
                )
            ''', args)
            return c.rowcount

    def execute(self):
        total = 0
        while True:
            cnt = self.execute_once()
            total += cnt
            if cnt < self.limit:
                break
        return total


class DropAnswers:
    max_answers = 1000

    def __init__(self, last_day, limit):
        self.last_day = last_day
        self.limit = limit

    def update_date_archived(self, survey_id, date_archived):
        args = (date_archived, survey_id)
        with get_rw_connection().cursor() as c:
            c.execute('''
                update surveyme_survey set date_archived = %s
                 where id = %s
            ''', args)


class DropDeletedAnswers(DropAnswers):
    def get_surveys(self):
        args = (self.last_day, self.limit)
        with get_ro_connection().cursor() as c:
            c.execute('''
                select t.id, ca.count
                  from surveyme_survey t
                  join countme_answercount ca on ca.survey_id = t.id
                 where (
                    t.is_deleted
                    and t.date_updated < %s
                    and (t.date_archived is null or t.date_archived < t.date_updated)
                    and ca.count > 0
                  )
                  limit %s
            ''', args)
            return c.fetchall()

    def get_dates(self, survey_id):
        args = (survey_id, )
        with get_ro_connection().cursor() as c:
            c.execute('''
                select t.created
                  from countme_answercountbydate t
                 where t.survey_id = %s
            ''', args)
            return c.fetchall()

    def drop_a_day(self, survey_id, day):
        finish = day + datetime.timedelta(days=1)
        args = (survey_id, day, finish, self.limit)
        while True:
            with get_rw_connection().cursor() as c:
                c.execute('''
                    delete from surveyme_profilesurveyanswer
                     where id in (
                         select id
                           from surveyme_profilesurveyanswer
                          where survey_id = %s
                            and date_created >= %s
                            and date_created < %s
                          limit %s
                    )
                ''', args)
                if c.rowcount < self.limit:
                    break

    def drop_day_by_day(self, survey_id):
        for (day, ) in self.get_dates(survey_id):
            self.drop_a_day(survey_id, day)

    def drop_at_once(self, survey_id):
        args = (survey_id, )
        with get_rw_connection().cursor() as c:
            c.execute('''
                delete from surveyme_profilesurveyanswer
                 where survey_id = %s
            ''', args)

    def execute(self):
        date_archived = self.last_day
        total = 0
        while True:
            cnt = 0
            for survey_id, answers in self.get_surveys():
                if answers > self.max_answers:
                    self.drop_day_by_day(survey_id)
                else:
                    self.drop_at_once(survey_id)
                self.update_date_archived(survey_id, date_archived)
                cnt += 1
            total += cnt
            if cnt < self.limit:
                break
        return total


class DropUnusedAnswers(DropAnswers):
    min_date = datetime.date(2018, 1, 1)

    def get_surveys(self):
        args = (self.last_day, self.last_day, self.last_day, self.limit)
        with get_ro_connection().cursor() as c:
            c.execute('''
                select t.id, t.date_archived, sum(c.count)
                  from surveyme_survey t
                  join countme_answercount ca on ca.survey_id = t.id
                  join countme_answercountbydate c on c.survey_id = t.id
                 where (
                   not t.is_deleted
                   and t.org_id is null
                   and (t.date_exported is null or t.date_exported < %s)
                   and (t.date_archived is null or t.date_archived < %s)
                   and c.created < %s
                   and (t.date_archived is null or c.created >= t.date_archived)
                 )
                 group by t.id
                 limit %s
            ''', args)
            return c.fetchall()

    def get_dates(self, survey_id, last_archived):
        last_archived = last_archived or self.min_date
        args = (survey_id, self.last_day, last_archived)
        with get_ro_connection().cursor() as c:
            c.execute('''
                select t.created
                  from countme_answercountbydate t
                 where t.survey_id = %s
                   and t.created < %s
                   and t.created >= %s
            ''', args)
            return c.fetchall()

    def drop_a_day(self, survey_id, day):
        finish = day + datetime.timedelta(days=1)
        args = (survey_id, day, finish, self.limit)
        while True:
            with get_rw_connection().cursor() as c:
                c.execute('''
                    delete from surveyme_profilesurveyanswer
                     where id in (
                         select id
                           from surveyme_profilesurveyanswer
                          where survey_id = %s
                            and date_created >= %s
                            and date_created < %s
                          limit %s
                    )
                ''', args)
                if c.rowcount < self.limit:
                    break

    def drop_day_by_day(self, survey_id, last_archived):
        for (day, ) in self.get_dates(survey_id, last_archived):
            self.drop_a_day(survey_id, day)

    def drop_at_once(self, survey_id, last_archived):
        last_archived = last_archived or self.min_date
        args = (survey_id, self.last_day, last_archived)
        with get_rw_connection().cursor() as c:
            c.execute('''
                delete from surveyme_profilesurveyanswer
                 where survey_id = %s
                   and date_created < %s
                   and date_created >= %s
            ''', args)

    def execute(self):
        date_archived = self.last_day
        total = 0
        while True:
            cnt = 0
            for survey_id, last_archived, answers in self.get_surveys():
                if answers > self.max_answers:
                    self.drop_day_by_day(survey_id, last_archived)
                else:
                    self.drop_at_once(survey_id, last_archived)
                self.update_date_archived(survey_id, date_archived)
                cnt += 1
            total += cnt
            if cnt < self.limit:
                break
        return total
