#!/usr/bin/python
#
# Copyright 2018-2020 Polyaxon, Inc.
#
# Licensed 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.

import polyaxon_sdk

from marshmallow import fields, validate

from polyaxon.lifecycle import V1Statuses
from polyaxon.polyflow.params import ParamSchema
from polyaxon.schemas.base import BaseCamelSchema, BaseConfig


class HookSchema(BaseCamelSchema):
    connection = fields.Str(required=True)
    trigger = fields.Str(
        allow_none=True, validate=validate.OneOf(V1Statuses.allowable_values)
    )
    hub_ref = fields.Str(allow_none=True)
    params = fields.Dict(
        keys=fields.Str(), values=fields.Nested(ParamSchema), allow_none=True
    )
    run_patch = fields.Dict(keys=fields.Str(), values=fields.Raw(), allow_none=True)

    @staticmethod
    def schema_config():
        return V1Hook


class V1Hook(BaseConfig, polyaxon_sdk.V1Hook):
    """You can configure Polyaxon to send notifications and webhooks to users and systems
    about event changes in your runs.

    Hooks also allow you to build or set up integrations and dependencies
    based on events generated by Polyaxon.
    External systems can subscribe or provide handling for certain events.
    When one of those events is triggered, Polyaxon will send an HTTP request
    payload to the webhook's configured URL.

    Polyaxon can send notifications when a run reaches a final status:

     * succeeded
     * failed
     * stopped
     * done (any final state)

     Args:
         connection: str
         trigger: str
         hub_ref: str, optional
         params: Dict[str, [V1Param](/docs/core/specification/params/)], optional
         run_patch: Dict, optional

    ## YAML usage

    ```yaml
    >>> hook:
    >>>   trigger: failed
    >>>   connection: slack-connection
    >>>   hubRef: custom-handler
    ```

    ## Python usage

    ```python
    >>> from polyaxon.lifecycle import V1Statuses
    >>> from polyaxon.polyflow import V1Hook
    >>> hook = V1Hook(
    >>>     trigger=V1Statuses.FAILED,
    >>>     hub_ref="slack",
    >>>     connection="slack-connection",
    >>> )
    ```

    ## Fields

    ### connection

    The connection to notify, this [connection](/docs/setup/connections/)
    must be configured at deployment time to be used here by referencing the name.

    ```yaml
    >>> hook:
    >>>   connection: slack-connection
    ```

    ### trigger

    The trigger represents the status condition to check before sending the notification.

    ```yaml
    >>> hook:
    >>>   trigger: succeeded
    ```

    In this example, the notification will be sent if the run succeeds.

    ### hubRef

    Polyaxon provides a [Component Hub](/docs/management/component-hub/)
    for hosting versioned components with an access control system to improve
    the productivity of your team.

    To trigger a hook based on a component hosted on Polyaxon Component Hub, you can use `hubRef`

    ```yaml
    >>> hook:
    >>>   hubRef: slack:v1
    ...
    ```

    Or custom hook component

    ```yaml
    >>> hook:
    >>>   hubRef:  my-component:dev
    ...
    ```

    ### params

    The [params](/docs/core/specification/params/) to pass if the handler requires extra params,
    they will be validated against the inputs/outputs.
    If a parameter is passed and the component does not define a corresponding inputs/outputs,
    a validation error will be raised unless the param has the contextOnly flag enabled.

    ```yaml
    >>> hook:
    >>>   params:
    >>>     param1: {value: 1.1}
    >>>     param2: {value: test}
    >>>   ...
    ```

    ### runPatch

    Component's environment section can be [patched](/docs/core/specification/operation/#runPatch).

    Example patching the container resources:

    ```yaml
    >>> hook:
    >>>   runPatch:
    >>>     container:
    >>>       resources:
    >>>         limits:
    >>>           cpu: 50m
    ```
    """

    IDENTIFIER = "hook"
    SCHEMA = HookSchema
    REDUCED_ATTRIBUTES = [
        "connection",
        "trigger",
        "hubRef",
        "params",
        "runPatch",
    ]
