#!/usr/bin/python
# Copyright 2017 Google Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type


ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}


DOCUMENTATION = '''
---
module: gcp_healthcheck
version_added: "2.4"
short_description: Create, Update or Destroy a Healthcheck.
description:
    - Create, Update or Destroy a Healthcheck. Currently only HTTP and
      HTTPS Healthchecks are supported. Healthchecks are used to monitor
      individual instances, managed instance groups and/or backend
      services. Healtchecks are reusable.
    - Visit
      U(https://cloud.google.com/compute/docs/load-balancing/health-checks)
      for an overview of Healthchecks on GCP.
    - See
      U(https://cloud.google.com/compute/docs/reference/latest/httpHealthChecks) for
      API details on HTTP Healthchecks.
    - See
      U(https://cloud.google.com/compute/docs/reference/latest/httpsHealthChecks)
      for more details on the HTTPS Healtcheck API.
requirements:
  - "python >= 2.6"
  - "google-api-python-client >= 1.6.2"
  - "google-auth >= 0.9.0"
  - "google-auth-httplib2 >= 0.0.2"
notes:
  - Only supports HTTP and HTTPS Healthchecks currently.
author:
  - "Tom Melendez (@supertom) <tom@supertom.com>"
options:
  check_interval:
    description:
       - How often (in seconds) to send a health check.
    required: false
    default: 5
  healthcheck_name:
    description:
       - Name of the Healthcheck.
    required: true
  healthcheck_type:
    description:
       - Type of Healthcheck.
    required: true
    choices: ["HTTP", "HTTPS"]
  host_header:
    description:
       - The value of the host header in the health check request. If left
         empty, the public IP on behalf of which this health
         check is performed will be used.
    required: true
    default: ""
  port:
    description:
       - The TCP port number for the health check request. The default value is
         443 for HTTPS and 80 for HTTP.
    required: false
  request_path:
    description:
       - The request path of the HTTPS health check request.
    required: false
    default: "/"
  state:
    description: State of the Healthcheck.
    required: true
    choices: ["present", "absent"]
  timeout:
    description:
       - How long (in seconds) to wait for a response before claiming
         failure. It is invalid for timeout
         to have a greater value than check_interval.
    required: false
    default: 5
  unhealthy_threshold:
    description:
       - A so-far healthy instance will be marked unhealthy after this
         many consecutive failures.
    required: false
    default: 2
  healthy_threshold:
    description:
       - A so-far unhealthy instance will be marked healthy after this
         many consecutive successes.
    required: false
    default: 2
  service_account_email:
    description:
      - service account email
    required: false
    default: null
  service_account_permissions:
    version_added: "2.0"
    description:
      - service account permissions (see
        U(https://cloud.go
ogle.com/sdk/gcloud/reference/compute/instances/create),
        --scopes section for detailed information)
    required: false
    default: null
    choices: [
      "bigquery", "cloud-platform", "compute-ro", "compute-rw",
      "useraccounts-ro", "useraccounts-rw", "datastore", "logging-write",
      "monitoring", "sql-admin", "storage-full", "storage-ro",
      "storage-rw", "taskqueue", "userinfo-email"
    ]
  credentials_file:
    description:
      - Path to the JSON file associated w
ith the service account email
    default: null
    required: false
  project_id:
    description:
      - Your GCP project ID
    required: false
    default: null
'''

EXAMPLES = '''
- name: Create Minimum HealthCheck
  gcp_healthcheck:
    service_account_email: "{{ service_account_email }}"
    credentials_file: "{{ credentials_file }}"
    project_id: "{{ project_id }}"
    healthcheck_name: my-healthcheck
    healthcheck_type: HTTP
    state: present
- name: Create HTTP HealthCheck
  gcp_healthcheck:
    service_account_email: "{{ service_account_email }}"
    credentials_file: "{{ credentials_file }}"
    project_id: "{{ project_id }}"
    healthcheck_name: my-healthcheck
    healthcheck_type: HTTP
    host: my-host
    request_path: /hc
    check_interval: 10
    timeout: 30
    unhealthy_threshhold: 2
    healthy_threshhold: 1
    state: present
- name: Create HTTPS HealthCheck
  gcp_healthcheck:
    service_account_email: "{{ service_account_email }}"
    credentials_file: "{{ credentials_file }}"
    project_id: "{{ project_id }}"
    healthcheck_name: "{{ https_healthcheck }}"
    healthcheck_type: HTTPS
    host_header: my-host
    request_path: /hc
    check_interval: 5
    timeout: 5
    unhealthy_threshold: 2
    healthy_threshold: 1
    state: present
'''

RETURN = '''
state:
    description: state of the Healthcheck
    returned: Always.
    type: str
    sample: present
healthcheck_name:
    description: Name of the Healthcheck
    returned: Always
    type: str
    sample: my-url-map
healthcheck_type:
    description: Type of the Healthcheck
    returned: Always
    type: str
    sample: HTTP
healthcheck:
    description: GCP Healthcheck dictionary
    returned: Always. Refer to GCP documentation for detailed field descriptions.
    type: dict
    sample: { "name": "my-hc", "port": 443, "requestPath": "/foo" }
'''

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.gcp import get_google_api_client, GCPUtils


USER_AGENT_PRODUCT = 'ansible-healthcheck'
USER_AGENT_VERSION = '0.0.1'


def _validate_healthcheck_params(params):
    """
    Validate healthcheck params.

    Simple validation has already assumed by AnsibleModule.

    :param params: Ansible dictionary containing configuration.
    :type  params: ``dict``

    :return: True or raises ValueError
    :rtype: ``bool`` or `class:ValueError`
    """
    if params['timeout'] > params['check_interval']:
        raise ValueError("timeout (%s) is greater than check_interval (%s)" % (
            params['timeout'], params['check_interval']))

    return (True, '')


def _build_healthcheck_dict(params):
    """
    Reformat services in Ansible Params for GCP.

    :param params: Params from AnsibleModule object
    :type params: ``dict``

    :param project_id: The GCP project ID.
    :type project_id:  ``str``

    :return: dictionary suitable for submission to GCP
             HealthCheck (HTTP/HTTPS) API.
    :rtype ``dict``
    """
    gcp_dict = GCPUtils.params_to_gcp_dict(params, 'healthcheck_name')
    if 'timeout' in gcp_dict:
        gcp_dict['timeoutSec'] = gcp_dict['timeout']
        del gcp_dict['timeout']

    if 'checkInterval' in gcp_dict:
        gcp_dict['checkIntervalSec'] = gcp_dict['checkInterval']
        del gcp_dict['checkInterval']

    if 'hostHeader' in gcp_dict:
        gcp_dict['host'] = gcp_dict['hostHeader']
        del gcp_dict['hostHeader']

    if 'healthcheckType' in gcp_dict:
        del gcp_dict['healthcheckType']
    return gcp_dict


def _get_req_resource(client, resource_type):
    if resource_type == 'HTTPS':
        return (client.httpsHealthChecks(), 'httpsHealthCheck')
    else:
        return (client.httpHealthChecks(), 'httpHealthCheck')


def get_healthcheck(client, name, project_id=None, resource_type='HTTP'):
    """
    Get a Healthcheck from GCP.

    :param client: An initialized GCE Compute Disovery resource.
    :type client:  :class: `googleapiclient.discovery.Resource`

    :param name: Name of the Url Map.
    :type name:  ``str``

    :param project_id: The GCP project ID.
    :type project_id:  ``str``

    :return: A dict resp from the respective GCP 'get' request.
    :rtype: ``dict``
    """
    try:
        resource, entity_name = _get_req_resource(client, resource_type)
        args = {'project': project_id, entity_name: name}
        req = resource.get(**args)
        retur