#!/usr/bin/python2.7
import os, sys
import auth, meter
from var_dump import var_dump
from pprint import pprint
sys.path.append("/var/www/cloudloon")
os.environ["DJANGO_SETTINGS_MODULE"] = "openstack_dashboard.settings"
from openstack_dashboard import settings
from openstack_dashboard.dashboards.admin.models import ResourceRates
from django.utils.timezone import utc
from datetime import datetime, timedelta
from bill.models import *
from subscription.models import Subscriber



class InitCreds:
    
    def __init__(self, **kwargs):
        self.meter_url = kwargs['meter_url']
        self.auth_url = kwargs['auth_url']
        self.admin_user = kwargs['admin_user']
        self.admin_pass = kwargs['admin_pass']
        self.admin_tenant = kwargs['admin_tenant']
        self.keystone = auth.KeystoneAuth(username=self.admin_user,
                                          password=self.admin_pass,
                                          tenant=self.admin_tenant,
                                          endpoint=self.auth_url)
        self.ceilo = meter.Meter(token=self.keystone.get_admin_token,
                                 endpoint=self.meter_url)

class Collector:
    
    def __init__(self):
        self.host = 'http://localhost'
        self.m_port = '8777'
        self.k_port = '5000'
        self.creds = InitCreds(meter_url='%s:%s' % (self.host, self.m_port),
                              auth_url='%s:%s/v2.0' % (self.host, self.k_port),
                              admin_user='admin',
                              admin_pass='abc',
                              admin_tenant='admin')
        self.keystone = self.creds.keystone
        self.ceilometer = self.creds.ceilo
        
    def __get_current_month_range(self):
        now = datetime.utcnow()
        start = datetime(now.year, now.month, 1, 0, 0, 1)
        return now, start
    
    def __format_timedelta(self, timedelta):
        hours, remainder = divmod(timedelta, 3600)  
        minutes, seconds = divmod(remainder, 60)   
        duration_formatted = '%s:%s:%s' % (hours, minutes, seconds)
        return duration_formatted
        
    def get_resource_rates(self):
        rates = ResourceRates.objects.all()
        data = {}
        for r in rates:
            data[r.type] = r.rate
        return data
        
    
    def __excempted_projects(self):
        data = ['alt_demo',
                'service',
                'demo',
                'admin',
                'invisible_to_admin']
        return data
    
    def get_tenants(self):
        tenants_list = self.keystone.get_all_tenant_id()
        system_projects = self.__excempted_projects()
        for s in system_projects:
             del tenants_list[s]
        return tenants_list
             
    def get_all_tenants_sample(self, meter, event_type=None):
        tenants_list = self.keystone.get_all_tenant_id()
        system_projects = self.__excempted_projects()
        data = {}
        for k, v in tenants_list.items():
            if k not in system_projects:
                samples = self.ceilometer.get_tenant_sample(v, meter, event_type)
                instances = []
                for s in samples:
                    this_sample = {}
                    this_sample['sample'] = s
                    stats = self.ceilometer.get_stats(s.resource_id, 
                                                      meter, 
                                                      period=None)
                    this_sample['stats'] = stats
                    instances.append(this_sample)
                data[v] = instances
        return data
    
    def to_hours(self, seconds):
        data = float(seconds) // 3600
        return data
    
    def get_instance_bill(self):
        instance_sample = self.get_all_tenants_sample('instance', 
                                                       event_type=None)
        data = {}
        for key, value in instance_sample.items():
            instance = []
            for s in value:
                this_sample = {}
                server = s['sample']
                server_stats = s['stats']
                duration_hours = float(server_stats[0].duration) // 3600
                metadata = server.resource_metadata
                this_sample['display_name'] = metadata['display_name']
                this_sample['resource_id'] = server.resource_id
                this_sample['flavor'] = metadata['flavor.name']
                this_sample['image'] = metadata['image.name']
                this_sample['reading_start'] = server_stats[0].duration_start
                this_sample['reading_end'] = server.timestamp
                for k, v in metadata.items():
                    rate = self.get_resource_rates().get(k)
                    if rate:
                        rate = (float(rate) * float(v)) * duration_hours
                        this_sample[k] = rate
                instance.append(this_sample)
            data[key] = instance
        return data
    
    def get_all_tenants_volume(self):
        tenants_list = self.keystone.get_all_tenant_id()
        system_projects = self.__excempted_projects()
        data = {}
        for k, v in tenants_list.items():
            if k not in system_projects:
                samples = self.ceilometer.get_volume_sample(tenant_id=v)
                data[v] = samples
        return data
    
    def get_volume_bill(self):
        tenants_volumes = self.get_all_tenants_volume()
        now, start = self.__get_current_month_range()
        reading_start = start
        reading_end = now
        rate = self.get_resource_rates()
        volume_rate = rate.get('volume.size')
        data = {}
        for key, value in tenants_volumes.items():
            volumes = value
            instance = []
            for vol in volumes:
                this_volume = {}
                metadata = vol.resource_metadata
                this_volume['display_name'] = metadata['display_name']
                this_volume['volume_size'] = metadata['size']
                this_volume['status'] = metadata['status']
                event_type = metadata['event_type']
#                 timestamp = now
                creation_date = datetime.strptime(metadata['created_at'], 
                                                           "%Y-%m-%d %H:%M:%S")
                if creation_date > start:
                    reading_start = creation_date
                if event_type == 'volume.delete.end' or event_type == 'volume.delete.start':
                    reading_end = datetime.strptime(vol.timestamp, 
                                                           "%Y-%m-%dT%H:%M:%S")
                duration = reading_end - reading_start
                duration_hour = duration.total_seconds() // 3600
                this_volume_rate = (float(volume_rate) * float(metadata['size'])) * duration_hour
                this_volume['volume'] = this_volume_rate
                this_volume['resource_id'] = vol.resource_id
                this_volume['creation_date'] = metadata['created_at']
                this_volume['reading_start'] = reading_start.strftime("%Y-%m-%dT%H:%M:%S")
                this_volume['reading_end'] = reading_end.strftime("%Y-%m-%dT%H:%M:%S")
                this_volume['duration'] = duration.total_seconds()
                instance.append(this_volume)
            data[key] = instance
        return data

# billing saving methods    
    def get_month_due_date(self):
        now = datetime.utcnow()
        end = datetime(now.year, now.month+1, 1, 23, 59, 59) - timedelta(days=1)
        return now, end
    
    def is_due(self):
        now, end = self.get_month_due_date()
        result = False
        if now.month == end.month and now.day == end.day:
            if now.hour == 23:
                result = True
        return result
    
    def __get_datetime_diff(self, fr, to):
        fr = datetime.strptime(fr, "%Y-%m-%dT%H:%M:%S")
        to = datetime.strptime(to, "%Y-%m-%dT%H:%M:%S")
        dif = to - fr
        dif = dif.total_seconds()
        return dif
    
    def __create_billing(self, tenant_id):
        now, end = self.get_month_due_date()
        due_date = end + timedelta(days=5)
        bill = False
        subscription = Subscriber.objects.get(subscriber=tenant_id)
        if subscription.is_active:
            bill = MonthlyBills(tenant_id=tenant_id,
                                        billing_due=due_date.replace(tzinfo=utc))
            bill.save()
        return bill
    
    def __create_instance_bill(self, bill_cls, object):
        """ object should be in dict type """
        usage_amount=0
        for key, value in object.items():
            try:
                rate = float(value)
                if rate:
                    usage_amount += rate
            except:
                pass
        usage_hours = self.__get_datetime_diff(object.get('reading_start', ''), 
                                                object.get('reading_end', ''))
        usage_hours = usage_hours // 3600
        
        instance = InstanceBill(monthlybills=bill_cls,
                                            resource_id=object.get('resource_id'),
                                            instance_name=object.get('display_name'),
                                            instance_image=object.get('image'),
                                            memory=object.get('flavor.ram'),
                                            root_gb=object.get('root_gb'),
                                            vpcu=object.get('flavor.vcpus'),
                                            usage_hours=usage_hours,
                                            usage_amount=usage_amount)
        try:
            instance.save()
            return instance
        except Exception as e:
            raise Exception(str(e))
        
    def __create_volume_bill(self, bill_cls, object):
        usage_hours = self.__get_datetime_diff(object.get('reading_start'), 
                                                object.get('reading_end', ''))
        usage_hours = float(object.get('duration', '')) // 3600
        
        volume = VolumeBill(monthlybills=bill_cls,
                                        resource_id=object.get('resource_id'),
                                        volume_name=object.get('display_name'),
                                        volume_size=object.get('volume_size'),
                                        usage_hours=usage_hours,
                                        usage_amount=float(object.get('volume')))
        try:
            volume.save()
            return volume
        except Exception as e:
            raise Exception(str(e))
            
    def create_tenants_bills(self):
        """ object list should be in list type """
#         client = Collector()
        if self.is_due():
            instances_bill = self.get_instance_bill()
            volumes_bill = self.get_volume_bill()
            for key, value in self.get_tenants().items():
                instances = instances_bill.get(value, '')
                volumes = volumes_bill.get(value, '')
                if len(instances) != 0 or len(volumes) != 0:
                    bill_cls = self.__create_billing(value)
                    if bill_cls:
                        if instances:
                            for ins in instances:
                                ins_bill = self.__create_instance_bill(bill_cls, ins)
                        if volumes:
                            for vol in volumes:
                                vols_bill = self.__create_volume_bill(bill_cls, vol)
    
def main():
    collector = Collector()
#     pprint(collector.get_all_tenants_sample('instance'))
            
    
if __name__ == "__main__": main()