from django.core.management.base import CommandError, BaseCommand
from askbot.models import User

# TODO: this command is broken - doesn't take into account UNIQUE constraints
#       and therefore causes db errors:
# In SQLite: "Warning: columns feed_type, subscriber_id are not unique"
# In MySQL: "Warning: (1062, "Duplicate entry 'm_and_c-2' for key 'askbot_emailfeedsetting_feed_type_6da6fdcd_uniq'")"
# In PostgreSQL: "Warning: duplicate key value violates unique constraint "askbot_emailfeedsetting_feed_type_6da6fdcd_uniq"
#                "DETAIL:  Key (feed_type, subscriber_id)=(m_and_c, 619) already exists."
#                (followed by series of "current transaction is aborted, commands ignored until end of transaction block" warnings)

class MergeUsersBaseCommand(BaseCommand):
    args = '<from_user_id> <to_user_id>'
    help = 'Merge an account and all information from a <user_id> to a <user_id>, deleting the <from_user>'

    def handle(self, *arguments, **options):

        self.parse_arguments(*arguments)

        for rel in User._meta.get_all_related_objects():
            try:
                self.process_field(rel.model, rel.field.name)
            except Exception, error:
                self.stdout.write(u'Warning: %s\n' % error)

        for rel in User._meta.get_all_related_many_to_many_objects():
            try:
                self.process_m2m_field(rel.model, rel.field.name)
            except Exception, error:
                self.stdout.write(u'Warning: %s\n' % error)

        self.process_custom_user_fields()

        self.cleanup() 

    def cleanup(self):
      raise Exception, 'Not implemented'
      
    def process_custom_user_fields(self):
      """Put app specific logic here."""
      raise Exception, 'Not implemented'

    def parse_arguments(self, *arguments):
        if len(arguments) != 2:
            raise CommandError('Arguments are <from_user_id> to <to_user_id>')
        self.from_user = User.objects.get(id = arguments[0])
        self.to_user = User.objects.get(id = arguments[1])

    def process_field(self, model, field_name):
        """reassigns the related object to the new user"""
        filter_condition = {field_name: self.from_user}
        related_objects_qs = model.objects.filter(**filter_condition)
        update_condition = {field_name: self.to_user}
        related_objects_qs.update(**update_condition)

    def process_m2m_field(self, model, field_name):
        """removes the old user from the M2M relation
        and adds the new user"""
        filter_condition = {field_name: self.from_user}
        related_objects_qs = model.objects.filter(**filter_condition)
        for obj in related_objects_qs:
            m2m_field = getattr(obj, field_name)
            m2m_field.remove(self.from_user)
            m2m_field.add(self.to_user)


class Command(MergeUsersBaseCommand):

  def process_custom_user_fields(self):
    self.to_user.reputation += self.from_user.reputation - 1
    self.to_user.gold += self.from_user.gold
    self.to_user.silver += self.from_user.silver
    self.to_user.bronze += self.from_user.bronze

    if self.from_user.last_seen > self.to_user.last_seen:
        self.to_user.last_seen = self.from_user.last_seen

    if self.from_user.date_joined < self.to_user.date_joined:
        self.to_user.date_joined = self.from_user.date_joined

  def cleanup(self):
    self.to_user.save()
    self.from_user.delete()

