# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
# 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.

from datetime import datetime
import socket
import ssl

from urllib.parse import urlparse

from monasca_agent.collector.checks import AgentCheck


class CertificateCheck(AgentCheck):
    """Uses ssl to get the SSL certificate and output a metric
       which is the number of days until it expires
    """

    def __init__(self, name, init_config, agent_config, instances=None):
        super(CertificateCheck, self).__init__(name, init_config,
                                               agent_config, instances)
        self._ca_certs = init_config.get('ca_certs')
        self._ciphers = init_config.get('ciphers')
        self._timeout = init_config.get('timeout')
        self.log.debug('ca_certs file is %s' % self._ca_certs)
        self.log.debug('cipers are %s' % self._ciphers)
        self.log.debug('timeout is %f' % self._timeout)

    def check(self, instance):
        url = instance.get('url', None)
        dimensions = self._set_dimensions(None, instance)
        dimensions['url'] = url
        self.log.info('url = %s' % url)
        try:
            expire_date = self.get_expire(url, self._ca_certs, self._ciphers,
                                          self._timeout)
            expire_in = expire_date - datetime.now()
            self.gauge('https.cert_expire_days', expire_in.days,
                       dimensions=dimensions)
            self.log.debug('%d days till expiration for %s' % (expire_in.days,
                                                               url))

        except Exception as e:
            self.log.warning('Exception trying to GET certificate for %s: %s' %
                             (url, e))
            self.log.exception('Failed to get certificate for %s' % url)

    def get_expire(self, url, ca_certs, ciphers, timeout):
        url_info = urlparse(url)
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        sock.connect((url_info.hostname, url_info.port))
        ssl_sock = ssl.wrap_socket(sock, cert_reqs=ssl.CERT_REQUIRED,
                                   ca_certs=ca_certs,
                                   ciphers=(ciphers))

        cert = ssl_sock.getpeercert()

        not_after = cert['notAfter']
        try:
            expire_date = datetime.strptime(not_after,
                                            '%b %d %H:%M:%S %Y %Z')
            return expire_date
        except ValueError:
            raise Exception('Invalid Certificate date format')
