# 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 datetime

from django.utils import timezone
from django.utils.translation import ugettext_lazy as _

from openstack_dashboard import api


def calc_period(date_from, date_to):
    if date_from and date_to:
        if date_to < date_from:
            # TODO(lsmola) propagate the Value error through Horizon
            # handler to the client with verbose message.
            raise ValueError(_("To date to must be greater than From date."))

        # get the time delta in seconds
        delta = date_to - date_from
        if delta.days <= 0:
            # it's one day
            delta_in_seconds = 3600 * 24
        else:
            delta_in_seconds = delta.days * 24 * 3600 + delta.seconds
            # Lets always show 400 samples in the chart. Know that it is
        # maximum amount of samples and it can be lower.
        number_of_samples = 400
        period = delta_in_seconds / number_of_samples
    else:
        # If some date is missing, just set static window to one day.
        period = 3600 * 24
    return period


def calc_date_args(date_from, date_to, date_options):
    if date_options == "other":
        if date_from and not isinstance(date_from, datetime.date):
            try:
                date_from = datetime.datetime.strptime(date_from,
                                                       "%Y-%m-%d")
            except Exception:
                raise ValueError(_("From-date is not recognized"))

        if date_to:
            if not isinstance(date_to, datetime.date):
                try:
                    date_to = datetime.datetime.strptime(date_to,
                                                         "%Y-%m-%d")
                except Exception:
                    raise ValueError(_("To-date is not recognized"))
        else:
            date_to = timezone.now()
    else:
        try:
            date_to = timezone.now()
            date_from = date_to - datetime.timedelta(days=int(date_options))
        except Exception:
            raise ValueError(_("The time delta must be an "
                             "integer representing days."))
    return date_from, date_to


class ProjectAggregatesQuery(object):
    def __init__(self, request, date_from, date_to,
                 period=None, additional_query=[]):
        if not period:
            period = calc_period(date_from, date_to)
        if date_from:
            additional_query.append({'field': 'timestamp',
                                     'op': 'ge',
                                     'value': date_from})
        if date_to:
            additional_query.append({'field': 'timestamp',
                                     'op': 'le',
                                     'value': date_to})

        self.request = request
        self.period = period
        self.additional_query = additional_query
        tenants, more = api.keystone.tenant_list(request,
                                                 domain=None,
                                                 paginate=False)
        self.queries = {}

        for tenant in tenants:
            tenant_query = [{
                            "field": "project_id",
                            "op": "eq",
                            "value": tenant.id}]

            self.queries[tenant.name] = tenant_query

    def query(self, meter):
        meter_list = [m for m in api.ceilometer.meter_list(self.request)
                      if m.name == meter]
        unit = ""
        if len(meter_list) > 0:
            unit = meter_list[0].unit
        ceilometer_usage = api.ceilometer.CeilometerUsage(self.request)
        resources = ceilometer_usage.resource_aggregates_with_statistics(
            self.queries, [meter], period=self.period,
            stats_attr=None,
            additional_query=self.additional_query)
        return resources, unit


class MeterQuery(ProjectAggregatesQuery):
    def __init__(self, *args, **kwargs):
        # pop filterfunc and add it later to self.
        filterfunc = kwargs.pop('filterfunc', None)
        super(MeterQuery, self).__init__(*args, **kwargs)
        self.filterfunc = filterfunc
        # Resetting the tenant based filter set in base class
        self.queries = None

    def query(self, meter):
        def filter_by_meter_name(resource):
            """Function for filtering of the list of resources.

            Will pick the right resources according to currently selected
            meter.
            """
            for link in resource.links:
                if link['rel'] == meter:
                    # If resource has the currently chosen meter.
                    return True
            return False

        meter_list = [m for m in api.ceilometer.meter_list(self.request)
                      if m.name == meter]

        unit = ""
        if len(meter_list) > 0:
            unit = meter_list[0].unit

        ceilometer_usage = api.ceilometer.CeilometerUsage(self.request)
        resources = ceilometer_usage.resources_with_statistics(
            self.queries, [meter],
            period=self.period,
            stats_attr=None,
            additional_query=self.additional_query,
            filter_func=filter_by_meter_name)

        return resources, unit
