from __future__ import absolute_import

import urlparse

from django import forms
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from django.core.validators import URLValidator
from django.http import HttpResponseRedirect

from sentry import http
from sentry.web.helpers import render_to_response
from sentry.identity.pipeline import IdentityProviderPipeline
from sentry.integrations import (
    IntegrationInstallation, IntegrationFeatures, IntegrationMetadata, IntegrationProvider, FeatureDescription,
)
from sentry.pipeline import (
    PipelineView, NestedPipelineView
)
from sentry.utils.http import absolute_uri

import pypd

DESCRIPTION = """
Connect your Sentry organization to your Pagerduty app, and start
getting alerts for errors right in front of you where all the
action happens in your office!
"""

FEATURES = [
    FeatureDescription(
        """
        Unfurls Sentry URLs directly within pagerduty, providing you context and
        actionability on issues right at your fingertips.
        """,
        IntegrationFeatures.CHAT_UNFURL,
    ),
    # to be done - as this requires custom actions from Pagerduty
    # FeatureDescription(
    #     """
    #     Resolve, ignore, and assign issues with minimal context switching.
    #     """,
    #     IntegrationFeatures.ACTION_NOTIFICATION,
    # ),
    FeatureDescription(
        """
        Configure rule based Pagerduty alerts to automatically be posted to a
        specific service/user. Want any error that's happening more than 100 times a
        minute to be posted with critical severity? Setup a rule for it!
        """,
        IntegrationFeatures.ALERT_RULE,
    ),
]

setup_alert = {
    'type': 'info',
    'text': 'The Pagerduty integration adds a new Alert Rule action to all projects. To enable automatic alerts sent to Pagerduty you must create a rule using the pagerduty account action in your project settings.',
}

metadata = IntegrationMetadata(
    description=_(DESCRIPTION.strip()),
    features=FEATURES,
    author='Kumarappan Arumugam',
    noun=_('Installation'),
    issue_url='https://github.com/kumarappan-arumugam/sentry-pagerduty/issues/new?title=Pagerduty%20Integration:%20&labels=Component%3A%20Integrations',
    source_url='https://github.com/kumarappan-arumugam/sentry-pagerduty/tree/master/sentry_pagerduty',
    aspects={
        'alerts': [setup_alert],
    }
)


class InstallationForm(forms.Form):
    service_name = forms.CharField(
        label="Provide a name of the pagerduty service for the integration",
        # choices=[],
        help_text=_('It will be easier to idenify the integration on the alert rules page with the name.'),
        widget=forms.TextInput(
            attrs={'placeholder': _('Pagerduty service name')}
        ),
    )
    api_key = forms.CharField(
        label="Pagerduty api Key",
        help_text=_('We require an api integration key to be '
                    'configured. This can be generated by following '
                    'the instructions at https://www.pagerduty.com/docs/guides/sentry-integration-guide'
                    ),
        widget=forms.TextInput(
            attrs={'placeholder': _('XXXXXXXXXXXXXXXXXXXXXXXXXXX')}
        )
    )

    def __init__(self, *args, **kwargs):
        super(InstallationForm, self).__init__(*args, **kwargs)

    def clean(self):
        """
        Hook for doing any extra form-wide cleaning after Field.clean() has been
        called on every field. Any ValidationError raised by this method will
        not be associated with a particular field; it will have a special-case
        association with the field named '__all__'.
        """
        super(InstallationForm, self).clean()

        api_key = self.cleaned_data.get('api_key')

        # this creates a test event to verify the api_key before storing
        try:
            result = pypd.EventV2.create(data={
                        'routing_key': api_key,
                        'event_action': 'trigger',
                        'payload': {
                            'summary': 'This is a test error event from sentry!',
                            'severity': 'info',
                            'source': 'Sentry',
                        }
                    })
        except Exception as e:
            raise forms.ValidationError(_("API key is not functional, test failed with error - %(error_class)s - %(error_message)s"),
                                        code='test-error',
                                        params={'error_message': e.message, 'error_class': type(e).__name__}
                                    )
        else:
            if not result['status'] == 'success':
                raise forms.ValidationError(_("API key is not functional, test failed"), code='test-error')

        return self.cleaned_data

class InstallationConfigView(PipelineView):
    def dispatch(self, request, pipeline):
        if request.method == 'POST':
            form = InstallationForm(request.POST)
            if form.is_valid():
                form_data = form.cleaned_data
                pipeline.bind_state('pagerduty', form_data)
                return pipeline.next_step()
        else:
            form = InstallationForm()

        return render_to_response(
            template='pagerduty-config.html',
            context={
                'form': form,
            },
            request=request,
        )

class PagerdutyIntegration(IntegrationInstallation):
    """
    An IntegrationInstallation represents an installed integration and manages the
    core functionality of the integration.
    """
    def get_client(self):
        # Return the api client for a given provider
        pypd.api_key = self.model.metadata['api_key']
        return pypd

class PagerdutyIntegrationProvider(IntegrationProvider):
    """
    An integration provider describes a third party that can be registered within Sentry.
    The core behavior is simply how to add the integration (the setup
    pipeline), which will likely use a nested pipeline for identity
    authentication, and what kind of configuration is stored.
    This is similar to Sentry's legacy 'plugin' information, except that an
    integration is lives as an instance in the database, and the ``IntegrationProvider``
    class is just a descriptor for how that object functions, and what behavior
    it provides (such as extensions provided).
    """

    key = 'pagerduty'
    name = 'Pagerduty'
    metadata = metadata
    features = frozenset([
        # IntegrationFeatures.ACTION_NOTIFICATION, # to be done - as this requires custom actions from pagerduty
        IntegrationFeatures.CHAT_UNFURL,
        IntegrationFeatures.ALERT_RULE,
    ])

    integration_cls = PagerdutyIntegration

    setup_dialog_config = {
        'width': 600,
        'height': 900,
    }

    def get_pipeline_views(self):
        return [InstallationConfigView(), PagerdutyFinishedView()]

    def build_integration(self, state):
        service_name = state['pagerduty'].get('service_name')
        integration = {
            'name': service_name,
            'external_id': service_name,
            'metadata': {
                'api_key': state['pagerduty']['api_key'],
            }
        }
        return integration

class PagerdutyFinishedView(PipelineView):
    def dispatch(self, request, pipeline):
        pipeline.finish_pipeline()

        messages.add_message(request, messages.SUCCESS, 'Pagerduty integration installed.')

        return HttpResponseRedirect(
            absolute_uri(u'/settings/{}/integrations/pagerduty/{}/'.format(
                pipeline.organization.slug,
                pipeline.integration.id,
            ))
        )
