# coding=utf-8
from outils.common import OdooAPI
import base64
import logging
from openpyxl import load_workbook
from io import BytesIO

coop_logger = logging.getLogger("coop.framework")


def make_csv_content_from_lines (rows):

    rows = sorted(rows, key=lambda x: x[0])
    csv_headers = ['Code journal', 'Date opération', 'N° pièce',
                       'N° compte', 'Libellé', 'Vide', 'Vide',
                       'Montant débit', 'Montant crédit']
    csv_content = ";".join(csv_headers) + "\r\n"
    sells_total = 0
    vat_total = 0
    selling_accounts = ['707011', '707101', '707102', '707201', '707202', '707301', '707302', '707303',
                        '707401', '707402', '707403', '707501', '707502', '707503', '707601', '707602', '707603',
                        '707701', '707702', '707703', '707801', '707802', '707803', '707901', '707902', '707903']
    vat_accounts = ['445711', '445712', '445713', '445714']
    for row in rows:
        row.append('')
        row[8] = row[7]
        row[7] = row[6]
        row[6] = ''
        if (row[0] == 'VEN'):
            row[4] = row[5]
            if row[3] in selling_accounts:
                if len(row[7]) > 0:
                    sells_total -= (float)(row[7].replace(',', '.'))
                if len(row[8]) > 0:
                    sells_total += (float)(row[8].replace(',', '.'))
            if row[3] in vat_accounts:
                if len(row[7]) > 0:
                    vat_total -= (float)(row[7].replace(',', '.'))
                if len(row[8]) > 0:
                    vat_total += (float)(row[8].replace(',', '.'))
        row[5] = ''
        csv_content += ";".join(row) + "\r\n"

    return {'csv_content': csv_content.encode(encoding="cp1252"),
            'sells_total': sells_total, 'vat_total': vat_total}


def make_daily_sell_accounts_sum(lines):
    other_than_sells = []
    sells = {}
    summed_lines = []

    for line in lines:
        if line[0] == 'VEN':
            if not (str(line[1]) in sells.keys()):
                sells[str(line[1])] = {}
            if not (str(line[3]) in sells[str(line[1])].keys()):
                sells[str(line[1])][str(line[3])] = {'D': 0.00, 'C': 0.00}
            amount = line[6]
            atype = 'D'
            if amount == '':
                amount = float(line[7].replace(',', '.'))
                atype = 'C'
            else:
                amount = float(line[6].replace(',', '.'))

            sells[str(line[1])][str(line[3])][atype] += amount

        else:
            other_than_sells.append(line)

    for day, accounts_data in sells.items():
        for account_num, dc_amounts in accounts_data.items():
            if dc_amounts['D'] > 0:
                c = ''
                d = round(dc_amounts['D'], 2)
                newline = (['VEN', day, 'Vente ' + day, account_num, '',
                            'Vente ' + day, d, c])
                summed_lines.append(newline)
            if dc_amounts['C'] > 0:
                d = ''
                c = round(dc_amounts['C'], 2)
                newline = (['VEN', day, 'Vente ' + day, account_num, '',
                            'Vente ' + day, d, c])
                summed_lines.append(newline)

    # on remplace les . des nombres flottants par des ,.
    i = 0
    while i < len(summed_lines):
        summed_lines[i][6] = str(summed_lines[i][6]).replace('.', ',')
        summed_lines[i][7] = str(summed_lines[i][7]).replace('.', ',')
        i += 1
    return summed_lines + other_than_sells


def make_daily_full_sum_up(lines):
    """Used to prepare Quadratus export, corresponding to SuperCafoutch needs."""

    try:
        ops = {'V': {}, 'K': {}}
        sales_jcode = ['BNK4', 'BNK5', 'BNK8', 'BNK9', 'CSH1', 'VEN']
        cap_jcode = ['CAP', 'CSH6', 'BNK3', 'BNK2', 'BNK1']
        summed_lines = {'V': [], 'K': []}

        for line in lines:
            k = ''
            d = '-'.join(reversed(str(line[1]).split('/')))  #  only yyyy-mm-dd date are alpha sortable
            account = str(line[3])
            if line[0] in sales_jcode:
                if line[0] == 'VEN':
                    j = 'VT'
                else:
                    j = 'RE'
                k = 'V'
            if line[0] in cap_jcode:
                if line[0] == 'CAP':
                    j = 'KA'
                else:
                    j = 'RE'
                k = 'K'
            if k != '':
                if not (d in ops[k].keys()):
                    # day entry
                    ops[k][d] = {}
                if not (j in ops[k][d].keys()):
                    # journal by day entry
                    ops[k][d][j] = {}

                if not (account in ops[k][d][j].keys()):
                    ops[k][d][j][account] = {'D': 0.00, 'C': 0.00}
                amount = line[6]
                atype = 'D'  # AccountType is Debit
                if amount == '':
                    amount = float(line[7].replace(',', '.'))
                    atype = 'C'  # AccountType is Credit
                else:
                    amount = float(line[6].replace(',', '.'))

                ops[k][d][j][account][atype] += amount


        for k, byday_data in ops.items():
            for day, journals_data in byday_data.items():
                for j_code, j_accounts in journals_data.items():
                    for account, amount in j_accounts.items():
                        if j_code == 'VT':
                            libelle = 'Vente ' + '/'.join(reversed(day.split('-')))
                        elif j_code == 'KA':
                            libelle = 'Capital'
                        else:
                            libelle = 'Reglement ' + '/'.join(reversed(day.split('-'))) # no accent because of ascii conversion mess (to fix)

                        if amount['D'] != 0 and amount['C'] != 0:
                            c = 0
                            d = int(float("{0:.2f}".format(amount['D'])) * 100)  # Quadratus export needs cents values
                            newline = ([j_code, day, libelle, account, '', libelle, d, c])
                            summed_lines[k].append(newline)
                            d = 0
                            c = int(float("{0:.2f}".format(amount['C'])) * 100)
                            newline = ([j_code, day, libelle, account, '', libelle, d, c])
                            summed_lines[k].append(newline)
                        else:
                            if amount['D'] != 0:
                                c = 0
                                d = int(float("{0:.2f}".format(amount['D'])) * 100)  # Quadratus export needs cents values
                            if amount['C'] != 0:
                                d = 0
                                c = int(float("{0:.2f}".format(amount['C'])) * 100)

                            newline = ([j_code, day, libelle, account, '', libelle, d, c])
                            summed_lines[k].append(newline)
    except Exception as e:
        coop_logger.error("compta, make_daily_full_sum_up : %s , %s", str(e), str(lines))

    return summed_lines

def retrieve_odoo_coop_data (coop_ids):
    api = OdooAPI()
    fields = ['name', 'barcode_base', 'id']
    cond = [['id', 'in', coop_ids]]
    coops = api.search_read('res.partner', cond, fields, 3000)

    coops_dict = {}
    for coop in coops:
        if not (str(coop['id']) in coops_dict.keys()):
            coops_dict[str(coop['id'])] = \
                str(coop['barcode_base']) + ' - ' + coop['name'].replace(';','')

    return coops_dict

def process_received_lines(received_data, coops, full_sumup=False):
    result = []
    # On reprend les lignes reçues pour substituer le nom des coop et
    # reprendre les colonnes debit / credit
    for line in received_data:
        line[7] = line[7].rstrip()
        if str(line[4]) in coops.keys():
            line[4] = coops[str(line[4])]
        if line[6] == '0':
            line[6] = line[7]
            line[7] = ''
        else:
            line[6] = ''
        result.append(line)
    if full_sumup is False:
        return make_daily_sell_accounts_sum(result)
    else:
        return make_daily_full_sum_up(result)

def generate_arithmethique_compatible_file (report):
    coop_ids = []
    received_data = []

    xlsx_content = base64.b64decode(report['datas'])
    excel_file = BytesIO(xlsx_content)
    workbook = load_workbook(excel_file, read_only=True)
    sheet = workbook.active

    #use min_row = 2 to skip headers
    for row in sheet.iter_rows(min_row=2, max_row=sheet.max_row, values_only=True):
        row = [str(item) for item in row]
        if len(row) == 8:
            if row[4] and row[4].isnumeric() and row[0] != 'VEN':
                if not (row[4] in coop_ids):
                    coop_ids.append(row[4])
            if not (row[0] == 'CAP' and row[3] == '101300' and row[5] != ""):
                received_data.append(row)
    coops = retrieve_odoo_coop_data(coop_ids)
    summarized_lines = process_received_lines(received_data, coops)
    res = make_csv_content_from_lines(summarized_lines)
    file_path = 'data/' + report['name'].replace(".xlsx", ".csv")
    file = open(file_path, 'wb')
    file.write(res['csv_content'])
    file.close()
    return {'file_path' : file_path, 'sells_total': res['sells_total'], 'vat_total': res['vat_total']}

def generate_quadratus_compatible_file(report):
    from .quadratus import generate_quadratus_file
    import zipfile
    import tempfile
    import io
    coop_ids = []
    received_data = []

    xlsx_content = base64.b64decode(report['datas'])
    excel_file = BytesIO(xlsx_content)
    workbook = load_workbook(excel_file, read_only=True)
    sheet = workbook.active

    #use min_row = 2 to skip headers
    for row in sheet.iter_rows(min_row=2, max_row=sheet.max_row, values_only=True):
        row = [str(item) for item in row]
        if len(row) == 8:
            if row[4] and row[4].isnumeric() and row[0] != 'VEN':
                if not (row[4] in coop_ids):
                    coop_ids.append(row[4])
            received_data.append(row)
    coops = retrieve_odoo_coop_data(coop_ids)
    summarized_lines = process_received_lines(received_data, coops, True)
    res = generate_quadratus_file(summarized_lines)
    files = []
    fsuffix = report['name'].replace(".xlsx", ".txt")
    if len(res['V']) > 0:
        vfn = 'data/ventes_' + fsuffix
        vf = open(vfn, 'wb')
        vf.write(res['V'])
        vf.close()
        files.append(vfn)
    if len(res['K']) > 0:
        kfn = 'data/capital_' + fsuffix
        kf = open(kfn, 'wb')
        kf.write(res['K'])
        kf.close()
        files.append(kfn)

    file_path = 'data/' + report['name'].replace(".xlsx", ".zip")
    with zipfile.ZipFile(file_path, 'w') as zipf:
        for f in files:
            zipf.write(f)

    # file = open(file_path, 'wb')
    # file.write(res)
    # file.close()

    return {'file_path': file_path}

def generate_odoo_export_file (date_from, date_to):
    """api user needs to have account_export right"""
    api = OdooAPI()

    params = {"name": "export_" + date_from + "_" + date_to,
              "filter_move_lines": "all", "extension": "csv", "config_id": 1,
              "date_from": date_from, "date_to": date_to}
    response = api.create("account.export", params)
    return response

def generate_account_export_report (export_id):
    api = OdooAPI()
    res = api.execute("account.export", 'create_report', [export_id])
    return res

def get_odoo_account_export_report (export_id, final_format):
    api = OdooAPI()
    report = None
    cond = [["res_model", "=", "account.export"], ["res_id", "=", export_id],["type", "in", ["binary"]]]
    res = api.search_read("ir.attachment", cond)
    if (res and len(res) > 0):
        if final_format == 'Quadratus':
            report = generate_quadratus_compatible_file(res[0])
        else:
            report = generate_arithmethique_compatible_file(res[0])
    return report

def get_members_capital_at_date(date,only_active):
    try:
        if only_active == 'on':
            only_active = 1
        else:
            only_active = 0
        return OdooAPI().execute("lacagette.exports", 'get_members_capital_at_date', {'date': date, 'only_active': only_active})
    except Exception as e:
        coop_logger.error("Erreur get_members_capital_at_date : %s", str(e))
        return {'error': "Erreur get_members_capital_at_date : " + str(e)}