#!/usr/bin/env python3

from decimal import Decimal, getcontext
# ~ getcontext().prec = 6

import lxml.etree as ET
from requests.structures import CaseInsensitiveDict as CIDict


NS_CFDI = {
    'cfdi': 'http://www.sat.gob.mx/cfd/3',
    'tfd': 'http://www.sat.gob.mx/TimbreFiscalDigital',
    'nomina12': 'http://www.sat.gob.mx/nomina12',
}
PRE = '/cfdi:Comprobante'


class CfdiRead(object):

    def __init__(self, source):
        self._source = source
        self._data = {}
        self._error = ''
        self._rfc_emisor = ''
        self._rfc_receptor = ''
        self._parse()

    @property
    def source(self):
        return self._source

    @property
    def data(self):
        return self._data

    @property
    def rfc_emisor(self):
        return self._rfc_emisor

    @property
    def rfc_receptor(self):
        return self._rfc_receptor

    @property
    def error(self):
        return self._error

    def _parse(self):
        self._tree = ET.fromstring(self.source)
        self._data['cfdi'] = dict(self._tree.attrib)

        node_name = f'{PRE}/cfdi:Emisor'
        self._data['emisor'] = self._get_attr(node_name)
        self._rfc_emisor = self._data['emisor']['Rfc']

        node_name = f'{PRE}/cfdi:Receptor'
        self._data['receptor'] = self._get_attr(node_name)
        self._rfc_receptor = self._data['receptor']['Rfc']

        node_name = f'{PRE}/cfdi:Complemento/tfd:TimbreFiscalDigital'
        self._data['timbre'] = self._get_attr(node_name)

        self._parse_details()
        return

    def _get_attr(self, node_name):
        node = self._tree.xpath(node_name, namespaces=NS_CFDI)[0]
        attr = dict(node.attrib)
        return attr

    def _parse_details(self):
        node_name = f'{PRE}/cfdi:Conceptos/cfdi:Concepto'
        details = self._tree.xpath(node_name, namespaces=NS_CFDI)
        rows = []
        for detail in details:
            row = dict(detail.attrib)
            for k, v in row.items():
                if k in ('Cantidad', 'ValorUnitario', 'Descuento', 'Importe'):
                    row[k] = Decimal(v)
            # ~ row['taxes'] = self._get_taxes(detail)
            rows.append(row)
        self._data['conceptos'] = rows
        return


class CfdiWrite(object):
    pass
