from datetime import date
from pprint import pprint  # noqa

from opensanctions.models import Entity, Alias, Identifier


ID_TYPES = {
    'diplomatic-passport': Identifier.TYPE_PASSPORT,
    'driving-license': Identifier.TYPE_OTHER,
    'driving-permit': Identifier.TYPE_OTHER,
    'id-card': Identifier.TYPE_NATIONALID,
    'other': Identifier.TYPE_OTHER,
    'passport': Identifier.TYPE_PASSPORT,
    'resident-permit': Identifier.TYPE_OTHER,
    'residence-permit': Identifier.TYPE_OTHER,
    'travel-document': Identifier.TYPE_PASSPORT
}

QUALITY = {
    'good': Alias.QUALITY_STRONG,
    'low': Alias.QUALITY_WEAK
}

NAME_PARTS = {
    'family-name': 'last_name',
    'given-name': 'first_name',
    'further-given-name': 'second_name',
    'father-name': 'father_name',
    'whole-name': 'name',
    'title': 'title',
    'grand-father-name': 'third_name',
    'tribal-name': 'last_name',
    'maiden-name': None,
    'other': None,
    'suffix': None,
}


def parse_date(el):
    if el is None or not el.get('year'):
        return
    if el.get('month') and el.get('day'):
        try:
            return date(int(el.get('year')),
                        int(el.get('month')),
                        int(el.get('day'))).isoformat()
        except ValueError:
            return date(int(el.get('year')),
                        int(el.get('month')),
                        int(el.get('day')) - 1).isoformat()
    else:
        return el.get('year')


def parse_address(entity, node, places):
    if not len(node.getchildren()):
        node = places.get(node.get('place-id'))
    address = entity.create_address()
    address.text = node.findtext('./location') or node.findtext('./c-o')
    address.note = node.findtext('./remarks')
    address.street = node.findtext('./address-details')
    address.street_2 = node.findtext('./p-o-box')
    address.postal_code = node.findtext('./zip-code')
    address.region = node.findtext('./area')

    country = node.find('./country')
    if country is not None:
        address.country = country.text
        if country.get('iso-code'):
            address.country_code = country.get('iso-code')


def parse_name(entity, node, main):
    quality = QUALITY[node.get('quality')]
    obj = entity
    if 'alias' == node.get('name-type') or not main:
        obj = entity.create_alias()
        obj.quality = quality

    variants = {}
    for part_node in node.findall('./name-part'):
        part_type = NAME_PARTS[part_node.get('name-part-type')]
        if part_type is None:
            continue

        value = part_node.findtext('./value')
        setattr(obj, part_type, value)

        for spelling in part_node.findall('./spelling-variant'):
            key = (spelling.get('lang'), spelling.get('script'))
            if key not in variants:
                variants[key] = entity.create_alias()
            setattr(variants[key], part_type, spelling.text)


def parse_identity(entity, node, places):
    main = node.get('main') == 'true'

    for name_node in node.findall('./name'):
        parse_name(entity, name_node, main)

    for address_node in node.findall('./address'):
        parse_address(entity, address_node, places)

    for bday_node in node.findall('./day-month-year'):
        birth_date = entity.create_birth_date()
        birth_date.date = parse_date(bday_node)
        birth_date.quality = QUALITY[bday_node.get('quality')]

    for place_node in node.findall('./place-of-birth'):
        res_place = places.get(place_node.get('place-id'))
        if place_node is None:
            continue

        birth_place = entity.create_birth_place()
        birth_place.quality = QUALITY[place_node.get('quality')]
        birth_place.place = res_place.findtext('./location')
        area = res_place.findtext('./area')
        if area is not None:
            if birth_place.place is not None:
                birth_place.place = '%s; %s' % (birth_place.place, area)
            else:
                birth_place.place = area

        country = res_place.find('./country')
        if country is not None:
            birth_place.country = country.text
            if country.get('iso-code') is not None:
                birth_place.country_code = country.get('iso-code')

    for doc in node.findall('./identification-document'):
        identifier = entity.create_identifier()
        identifier.number = doc.findtext('./number')
        identifier.description = doc.get('document-type')
        identifier.type = ID_TYPES[identifier.description]
        country = doc.find('./issuer')
        if country is not None:
            identifier.country = country.text
            if country.get('code'):
                identifier.country_code = country.get('code')


def parse_entry(context, target, updated_at, sanctions, places):
    node = target.find('./individual')
    type_ = Entity.TYPE_INDIVIDUAL
    if node is None:
        node = target.find('./entity')
        type_ = Entity.TYPE_ENTITY
    if node is None:
        # node = target.find('./object')
        # TODO: build out support for these!
        return

    entity = Entity.create('ch-seco-sanctions', target.get('ssid'))
    entity.type = type_
    entity.updated_at = updated_at
    entity.program = sanctions.get(target.get('sanctions-set-id'))
    entity.function = node.findtext('./other-information')
    entity.summary = node.findtext('./justification')

    for inode in node.findall('./identity'):
        parse_identity(entity, inode, places)

    # pprint(entity.to_dict())
    context.emit(data=entity.to_dict())


def seco_parse(context, data):
    res = context.http.rehash(data)
    doc = res.xml
    updated_at = doc.getroot().get('date')

    programs = {}
    for sanc in doc.findall('.//sanctions-program'):
        key = sanc.find('./sanctions-set').get('ssid')
        label = sanc.findtext('./program-name[@lang="eng"]')
        programs[key] = label

    places = {}
    for place in doc.findall('.//place'):
        places[place.get('ssid')] = place

    for target in doc.findall('./target'):
        parse_entry(context, target, updated_at, programs, places)

from datetime import date
from pprint import pprint  # noqa

from opensanctions.models import Entity, Alias, Identifier


ID_TYPES = {
    'diplomatic-passport': Identifier.TYPE_PASSPORT,
    'driving-license': Identifier.TYPE_OTHER,
    'driving-permit': Identifier.TYPE_OTHER,
    'id-card': Identifier.TYPE_NATIONALID,
    'other': Identifier.TYPE_OTHER,
    'passport': Identifier.TYPE_PASSPORT,
    'resident-permit': Identifier.TYPE_OTHER,
    'residence-permit': Identifier.TYPE_OTHER,
    'travel-document': Identifier.TYPE_PASSPORT
}

QUALITY = {
    'good': Alias.QUALITY_STRONG,
    'low': Alias.QUALITY_WEAK
}

NAME_PARTS = {
    'family-name': 'last_name',
    'given-name': 'first_name',
    'further-given-name': 'second_name',
    'father-name': 'father_name',
    'whole-name': 'name',
    'title': 'title',
    'grand-father-name': 'third_name',
    'tribal-name': 'last_name',
    'maiden-name': None,
    'other': None,
    'suffix': None,
}


def parse_date(el):
    if el is None or not el.get('year'):
        return
    if el.get('month') and el.get('day'):
        try:
            return date(int(el.get('year')),
                        int(el.get('month')),
                        int(el.get('day'))).isoformat()
        except ValueError:
            return date(int(el.get('year')),
                        int(el.get('month')),
                        int(el.get('day')) - 1).isoformat()
    else:
        return el.get('year')


def parse_address(entity, node, places):
    if not len(node.getchildren()):
        node = places.get(node.get('place-id'))
    address = entity.create_address()
    address.text = node.findtext('./location') or node.findtext('./c-o')
    address.note = node.findtext('./remarks')
    address.street = node.findtext('./address-details')
    address.street_2 = node.findtext('./p-o-box')
    address.postal_code = node.findtext('./zip-code')
    address.region = node.findtext('./area')

    country = node.find('./country')
    if country is not None:
        address.country = country.text
        if country.get('iso-code'):
            address.country_code = country.get('iso-code')


def parse_name(entity, node, main):
    quality = QUALITY[node.get('quality')]
    obj = entity
    if 'alias' == node.get('name-type') or not main:
        obj = entity.create_alias()
        obj.quality = quality

    variants = {}
    for part_node in node.findall('./name-part'):
        part_type = NAME_PARTS[part_node.get('name-part-type')]
        if part_type is None:
            continue

        value = part_node.findtext('./value')
        setattr(obj, part_type, value)

        for spelling in part_node.findall('./spelling-variant'):
            key = (spelling.get('lang'), spelling.get('script'))
            if key not in variants:
                variants[key] = entity.create_alias()
            setattr(variants[key], part_type, spelling.text)


def parse_identity(entity, node, places):
    main = node.get('main') == 'true'

    for name_node in node.findall('./name'):
        parse_name(entity, name_node, main)

    for address_node in node.findall('./address'):
        parse_address(entity, address_node, places)

    for bday_node in node.findall('./day-month-year'):
        birth_date = entity.create_birth_date()
        birth_date.date = parse_date(bday_node)
        birth_date.quality = QUALITY[bday_node.get('quality')]

    for place_node in node.findall('./place-of-birth'):
        res_place = places.get(place_node.get('place-id'))
        if place_node is None:
            continue

        birth_place = entity.create_birth_place()
        birth_place.quality = QUALITY[place_node.get('quality')]
        birth_place.place = res_place.findtext('./location')
        area = res_place.findtext('./area')
        if area is not None:
            if birth_place.place is not None:
                birth_place.place = '%s; %s' % (birth_place.place, area)
            else:
                birth_place.place = area

        country = res_place.find('./country')
        if country is not None:
            birth_place.country = country.text
            if country.get('iso-code') is not None:
                birth_place.country_code = country.get('iso-code')

    for doc in node.findall('./identification-document'):
        identifier = entity.create_identifier()
        identifier.number = doc.findtext('./number')
        identifier.description = doc.get('document-type')
        identifier.type = ID_TYPES[identifier.description]
        country = doc.find('./issuer')
        if country is not None:
            identifier.country = country.text
            if country.get('code'):
                identifier.country_code = country.get('code')


def parse_entry(context, target, updated_at, sanctions, places):
    node = target.find('./individual')
    type_ = Entity.TYPE_INDIVIDUAL
    if node is None:
        node = target.find('./entity')
        type_ = Entity.TYPE_ENTITY
    if node is None:
        # node = target.find('./object')
        # TODO: build out support for these!
        return

    entity = Entity.create('ch-seco-sanctions', target.get('ssid'))
    entity.type = type_
    entity.updated_at = updated_at
    entity.program = sanctions.get(target.get('sanctions-set-id'))
    entity.function = node.findtext('./other-information')
    entity.summary = node.findtext('./justification')

    for inode in node.findall('./identity'):
        parse_identity(entity, inode, places)

    # pprint(entity.to_dict())
    context.emit(data=entity.to_dict())


def seco_parse(context, data):
    res = context.http.rehash(data)
    doc = res.xml
    updated_at = doc.getroot().get('date')

    programs = {}
    for sanc in doc.findall('.//sanctions-program'):
        key = sanc.find('./sanctions-set').get('ssid')
        label = sanc.findtext('./program-name[@lang="eng"]')
        programs[key] = label

    places = {}
    for place in doc.findall('.//place'):
        places[place.get('ssid')] = place

    for target in doc.findall('./target'):
        parse_entry(context, target, updated_at, programs, places)

# noqa # node = target.find('./object') # TODO: build out support for these! # pprint(entity.to_dict())