#       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 datetime import (
        datetime,
        timedelta,
        )
import json

from formencode import validators as fev

from ming.orm import session
from pylons import tmpl_context as c
from pylons import app_globals as g
from tg import (
        config,
        expose,
        flash,
        redirect,
        validate,
        )
from tg.decorators import (
        with_trailing_slash,
        without_trailing_slash,
        )

from allura.controllers import BaseController
from allura.lib.decorators import require_post, task
from allura.lib.import_api import AlluraImportApiClient
from allura.lib import validators as v
from allura.lib import helpers as h
from allura.model import ApiTicket, AuditLog
from allura.scripts.trac_export import (
        TracExport,
        DateJSONEncoder,
        )

from forgeimporters.base import (
        ToolImporter,
        ToolImportForm,
        ImportErrorHandler,
        )
from forgetracker.tracker_main import ForgeTrackerApp
from forgetracker.scripts.import_tracker import import_tracker


@task(notifications_disabled=True)
def import_tool(**kw):
    importer = TracTicketImporter()
    with ImportErrorHandler(importer, kw.get('trac_url'), c.project):
        importer.import_tool(c.project, c.user, **kw)


class TracTicketImportForm(ToolImportForm):
    trac_url = fev.URL(not_empty=True)
    user_map = v.UserMapJsonFile(as_string=True)


class TracTicketImportController(BaseController):
    def __init__(self):
        self.importer = TracTicketImporter()
        self.task = import_tool

    @property
    def target_app(self):
        return self.importer.target_app

    @with_trailing_slash
    @expose('jinja:forgeimporters.trac:templates/tickets/index.html')
    def index(self, **kw):
        return dict(importer=self.importer,
                target_app=self.target_app)

    @without_trailing_slash
    @expose()
    @require_post()
    @validate(TracTicketImportForm(ForgeTrackerApp), error_handler=index)
    def create(self, trac_url, mount_point, mount_label, user_map=None, **kw):
        if self.importer.enforce_limit(c.project):
            self.task.post(
                    mount_point=mount_point,
                    mount_label=mount_label,
                    trac_url=trac_url,
                    user_map=user_map)
            flash('Ticket import has begun. Your new tracker will be available '
                    'when the import is complete.')
        else:
            flash('There are too many imports pending at this time.  Please wait and try again.', 'error')
        redirect(c.project.url() + 'admin/')


class TracTicketImporter(ToolImporter):
    target_app = ForgeTrackerApp
    source = 'Trac'
    controller = TracTicketImportController
    tool_label = 'Tickets'
    tool_description = 'Import your tickets from Trac'

    def import_tool(self, project, user, project_name=None, mount_point=None,
            mount_label=None, trac_url=None, user_map=None, **kw):
        """ Import Trac tickets into a new Allura Tracker tool.

        """
        trac_url = trac_url.rstrip('/') + '/'
        mount_point = mount_point or 'tickets'
        app = project.install_app(
                'Tickets',
                mount_point=mount_point,
                mount_label=mount_label or 'Tickets',
                open_status_names='new assigned accepted reopened',
                closed_status_names='closed',
                import_id={
                        'source': self.source,
                        'trac_url': trac_url,
                    },
            )
        session(app.config).flush(app.config)
        session(app.globals).flush(app.globals)
        try:
            export = [ticket for ticket in TracExport(trac_url)]
            export_string = json.dumps(export, cls=DateJSONEncoder)
            api_ticket = ApiTicket(user_id=user._id,
                    capabilities={"import": ["Projects", project.shortname]},
                    expires=datetime.utcnow() + timedelta(minutes=60))
            session(api_ticket).flush(api_ticket)
            cli = AlluraImportApiClient(config['base_url'], api_ticket.api_key,
                    api_ticket.secret_key, verbose=True, retry=False)
            import_tracker(cli, project.shortname, mount_point, {
                        'user_map': json.loads(user_map) if user_map else {},
                        'usernames_match': self.usernames_match(trac_url),
                    },
                    export_string, validate=False)
            AuditLog.log(
                'import tool %s from %s' % (
                        app.config.options.mount_point,
                        trac_url,
                    ),
                project=project, user=user, url=app.url,
            )
            g.post_event('project_updated')
            return app
        except Exception:
            h.make_app_admin_only(app)
            raise

    def usernames_match(self, trac_url):
        """Return True if the usernames in the source Trac match the usernames
        in the destination Allura instance.

        If this is True, Trac usernames will be mapped to their Allura
        counterparts regardless of whether a user_map file is supplied.

        If this is False, any Trac username not present in the user_map file
        (or if no file is supplied) will be assumed an unknown or non-existent
        user in the Allura instance.

        """
        return False
