#!/usr/bin/env python3
import csv
import os
import sys
from email.message import Message
from email.policy import SMTPUTF8
from functools import partial
import re
import horetu
import horetu.types as T

def seltzer(fp):
    import lxml.html
    keys = ('name', 'membership', 'email', 'phone')

    html = lxml.html.fromstring(fp.buffer.read())
    for tr in html.xpath('//table/tbody/tr'):
        values = (td.text_content().strip().replace('\r', '') for td in tr.xpath('td'))
        row = dict(zip(keys, values))
        row['name'] = re.sub(r'([^,]+), (.+)', r'\2 \1', row['name'])
        del(row['membership'])
        yield row['name'].replace('.', '').replace(' ', '.').lower(), row

def _aliases(with_name, without_name, fp):
    for line in fp:
        m = re.match(with_name, line)
        if m:
            identifier, name, email = m.groups()
            yield identifier.strip(), {
                'name': name.strip(),
                'email': email.strip(),
            }
        else:
            m = re.match(without_name, line)
            if m:
                identifier, email = m.groups()
                yield identifier.strip(), {
                    'email': email.strip(),
                }

mh = partial(_aliases,
             re.compile(r'([^:]+): *([^<]+)<([^> ]*)>.*'),
             re.compile(r'([^:]+): *([^ <>]+)'))

mutt = partial(_aliases,
               re.compile(r'^alias ([^ ]+) +(.+) ([^ ]+)$'),
               re.compile(r'^alias ([^ ]+) +([^ ]+)$'))

def voipms(fp):
    reader = csv.reader(fp)
    for speeddial, name, phone in reader:
        identifier = name.replace(' ', '.').lower()
        yield identifier, {'name': name, 'phone': phone}

FORMATS = {
    'mh': mh,
    'mutt': mutt,
    'voipms': voipms,
    'seltzer': seltzer,
}
MODES = ('a', 'w')

def parse(input_format: FORMATS,
          fin: T.InputFile=sys.stdin, dout: T.OutputDirectory='.',
          *, dry=False, mode: MODES='w'):
    '''
    Convert data from a single file in a different format to a directory
    of bguo format files.

    :param input_format: "mh" to read an MH ~/.aliases file, "voipms" to
        read a CSV export from voip.ms, or "seltzer" to read an HTML
        file generated by the seltzer CRM members page ("/?q=members")
    :param fin: Input file, or STDIN by default
    :param dout: Output directory, or the current directory by default
    :param bool dry: Write no files, but print what files would have been written.
    :param mode: "w" to write only new files, skipping existing files,
        or "a" to append to existing files
    '''
    for identifier, record in input_format(fin):
        m = Message(policy=SMTPUTF8)
        for k, v in record.items():
            m[k] = v
        filename = os.path.join(dout, identifier)
        text = str(m).strip().replace('\r', '') + '\n'
 
        if mode=='a':
            if dry:
                sys.stdout.write('Append to %s:\n%s\n' % (filename, text))
            else:
                with open(filename, 'a') as fout:
                    fout.write(text)
        elif mode=='w' and not os.path.exists(filename):
            if dry:
                sys.stdout.write('Create %s:\n%s\n' % (filename, text))
            else:
                with open(filename, 'w') as fout:
                    fout.write(text)
        else:
            if dry:
                sys.stdout.write('Skip writing to %s\n' % filename)
