#!/usr/bin/env python3

# By: Riasat Ullah
# This class processes bills.
import sys

sys.path.append('/var/www/html/taskcallrest/')

from billings.bill_manager import BillManager
from dbqueries import db_billings
from templates.invoice import Invoice
from utils import constants, informational_content, logging, mail, payment_vendors, times, var_names
from utils.db_connection import CONN_POOL
import argparse
import datetime


class SubscriptionPaymentProcessor(object):

    def __init__(self, conn, timestamp, skip_organizations=None):
        self.conn = conn
        self.timestamp = timestamp
        self.last_month_tmsp = self.timestamp - datetime.timedelta(self.timestamp.day)
        self.skip_organizations = skip_organizations

    def process(self):
        bill_manager = BillManager(self.conn, self.timestamp, self.last_month_tmsp.year, self.last_month_tmsp.month)
        all_bills = bill_manager.create_bills(skip_organizations=self.skip_organizations)

        try:
            db_billings.book_bills_only(self.conn, self.timestamp, all_bills)
        except RuntimeError as e:
            logging.error(str(e))

        processed_charges = []
        unprocessed_charges = []
        open_charges = db_billings.get_open_charges(self.conn, self.timestamp, bill_manager.organization_ids)
        stripe_api_key = payment_vendors.get_stripe_token(secret_key=True)
        for charge in open_charges:
            confirmation = None
            attempt = 1
            try:
                while confirmation is None and attempt <= 2:
                    confirmation = payment_vendors.create_stripe_payment_intent(
                        charge.card_token[var_names.customer_id], charge.card_token[var_names.payment_method],
                        charge.currency, charge.amount, stripe_api_key
                    )
                    attempt += 1
            except Exception as e:
                logging.exception(str(e))
                unprocessed_charges.append(charge)

            if confirmation is not None:
                charge.payment_confirmation = confirmation
                processed_charges.append(charge)

        if len(processed_charges) > 0:
            db_billings.book_charges(self.conn, self.timestamp, processed_charges)
            logging.info('Processed charges - ' + str([item.charge_id for item in processed_charges]))
        else:
            logging.info('No payment charges were found for processing.')

        if len(unprocessed_charges) > 0:
            logging.info('FAILED - Unprocessed charges - ' + str(unprocessed_charges))

        # Email the invoices to the account owners
        self.email_invoices(bill_manager.billing_year, bill_manager.billing_month,
                            organization_ids=bill_manager.organization_ids)

    def email_invoices(self, billing_year, billing_month, organization_ids=None):
        logging.info('Emailing invoices to account owners...')
        bill_details = db_billings.get_bill_details(self.conn, organization_id=organization_ids,
                                                    bill_year=billing_year, bill_month=billing_month)
        email_credentials = mail.AmazonSesCredentials(constants.billings_email_account)

        for item in bill_details:
            item[var_names.bill_id] = str(item[var_names.bill_id]).zfill(9)
            tmp_storage_loc = '/tmp/Invoice_' + item[var_names.bill_id] + '.pdf'

            # create the invoice first
            try:
                inv = Invoice()
                inv.create_pdf(tmp_storage_loc, item)

                # Email the invoice
                month_year_text = item[var_names.start_period].strftime('%B %Y')
                subject, content = informational_content.invoice_email_content(
                    month_year_text, item[var_names.organization_name], item[var_names.bill_id])
                mail.AmazonSesDispatcher(subject, content, item[var_names.email], email_credentials,
                                         attachments=[tmp_storage_loc], delete_attachments=True,
                                         with_cc=item[var_names.additional_emails]).start()
            except Exception as e:
                logging.info('Skipping email - ' + item[var_names.email])
                logging.info(str(e))


if __name__ == '__main__':
    arg_parser = argparse.ArgumentParser()
    arg_parser.add_argument('--processing_time', default=None)
    arg_parser.add_argument('--skip_organizations', nargs='+', default=None)

    args = arg_parser.parse_args()
    processing_time = args.processing_time
    skip_orgs = args.skip_organizations

    if processing_time is None:
        processing_time = times.get_current_timestamp()
    else:
        assert (isinstance(processing_time, datetime.datetime) or isinstance(processing_time, str))
        if type(processing_time) is str:
            processing_time = datetime.datetime.strptime(processing_time, constants.timestamp_format)

    if skip_orgs is not None:
        skip_orgs = [int(x) for x in skip_orgs]

    processor_conn = CONN_POOL.get_db_conn()

    processor = SubscriptionPaymentProcessor(processor_conn, processing_time, skip_organizations=skip_orgs)
    processor.process()

    CONN_POOL.put_db_conn(processor_conn)
