#       Licensed to the Apache Software Foundation (ASF) under one
#       or more contributor license agreements.  See the NOTICE file
#       distributed with this work for additional information
#       regarding copyright ownership.  The ASF licenses this file
#       to you under the Apache License, Version 2.0 (the
#       "License"); you may not use this file except in compliance
#       with the License.  You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#       Unless required by applicable law or agreed to in writing,
#       software distributed under the License is distributed on an
#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#       KIND, either express or implied.  See the License for the
#       specific language governing permissions and limitations
#       under the License.

from bson import ObjectId
from bson.errors import InvalidId
from ming.odm import ThreadLocalODMSession
from tg import tmpl_context as c

from allura.command import base
from allura import model as M
from allura.lib import exceptions as exc
from forgetracker.model import Ticket


class FixDiscussion(base.Command):

    """Fixes trackers that had used buggy 'ticket move' feature before it was fixed.

    See [#5727] for details.

    Usage:

    paster fix-discussion ../Allura/development.ini [project_name_or_id]

    If used with optional parameter will fix trackers for specified project,
    else will fix all trackers in all projects.
    """
    group_name = 'ForgeTracker'
    min_args = 1
    max_args = 2
    usage = '<ini file> [project_name_or_id]'
    summary = "Fix trackers that had used buggy 'ticket move' feature"
    parser = base.Command.standard_parser(verbose=True)

    def command(self):
        self.basic_setup()

        if len(self.args) >= 2:
            p_name_or_id = self.args[1]
            try:
                project = M.Project.query.get(_id=ObjectId(p_name_or_id))
            except InvalidId:
                projects = M.Project.query.find({'$or': [
                    {'shortname': p_name_or_id},
                    {'name': p_name_or_id}
                ]})
                if projects.count() > 1:
                    raise exc.ForgeError('Multiple projects has a shortname %s. '
                                         'Use project _id instead.' % p_name_or_id)
                project = projects.first()
            if not project:
                raise exc.NoSuchProjectError('The project %s '
                                             'could not be found' % p_name_or_id)

            self.fix_for_project(project)
        else:
            base.log.info(
                'Checking discussion instances for each tracker in all projects')
            for project in M.Project.query.find():
                self.fix_for_project(project)

    def fix_for_project(self, project):
        c.project = project
        base.log.info(
            'Checking discussion instances for each tracker in project %s' %
            project.shortname)
        trackers = [ac for ac in project.app_configs
                    if ac.tool_name.lower() == 'tickets']
        for tracker in trackers:
            base.log.info('Found tracker %s' % tracker)
            for ticket in Ticket.query.find({'app_config_id': tracker._id}):
                base.log.info('Processing ticket %s [#%s] %s'
                              % (ticket._id, ticket.ticket_num, ticket.summary))
                if ticket.discussion_thread.discussion.app_config_id != tracker._id:
                    # Some tickets were moved from this tracker,
                    # and Discussion instance for entire tracker was moved too.
                    # Should move it back.
                    base.log.info("Some tickets were moved from this tracker. "
                                  "Moving tracker's discussion instance back.")
                    ticket.discussion_thread.discussion.app_config_id = tracker._id

                if ticket.discussion_thread.discussion_id != tracker.discussion_id:
                    # Ticket was moved from another tracker.
                    # Should bind his comment thread to tracker's Discussion
                    base.log.info("Ticket was moved from another tracker. "
                                  "Bind ticket's comment thread to tracker's Discussion instance.")
                    ticket.discussion_thread.discussion_id = tracker.discussion_id
                    for post in ticket.discussion_thread.posts:
                        post.discussion_id = tracker.discussion_id

            ThreadLocalODMSession.flush_all()
