import argparse
import yaml
import locale

from pathlib import Path, PurePath
from datetime import datetime

from invoice_generator import html_generator


class DataObject:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)


def parse_yaml_file(file_path):
    with open(file_path, 'r', encoding='utf-8') as file:
        return yaml.safe_load(file)


def check_file(file_path):
    try_out_extensions = ['.yaml', '.yml']

    for ext in try_out_extensions:
        if file_path.exists():
            return file_path
        file_path = file_path.with_suffix(ext)
    return None


def parse_date(date_string):
    return datetime.strptime(date_string, '%Y-%m-%d').date()


def merge_envelope_data_into_invoice_data(invoice_data, source_data):
    if (source_data is None) or (invoice_data is None):
        return
    for key, value in source_data.items():
        if not hasattr(invoice_data, key):
            setattr(invoice_data, key, value)


# Utility function


def main():
    locale.setlocale(locale.LC_ALL, 'de_DE.utf8')

    cwd = Path.cwd().resolve()

    print('Simple invoice generator for freelancers and small businesses by Torsten Ueberschar')
    print()
    parser = argparse.ArgumentParser(description='Read invoice and envelope data from yaml file')
    parser.add_argument('-b', '--base', type=str, required=False, default=cwd,
                        help='base directory for invoice and envelope files (default: (current working directory) %(default)s)')
    parser.add_argument('-e', '--envelope', type=str, required=False, default='envelope.yaml',
                        help='Envelope file name (default: %(default)s)')
    parser.add_argument('-t', '--template', type=str, required=False, default='templates',
                        help='directory for template files (default: %(default)s)')
    parser.add_argument('-i', '--invoice', type=str, required=True, help='Invoice file name')

    args = parser.parse_args()

    invoice_file = args.invoice
    envelope_file = args.envelope

    print(f'Searching for invoice files in: {args.base}')

    invoice_file = Path(args.base) / invoice_file
    envelope_file = Path(args.base) / envelope_file

    invoice_file = check_file(invoice_file)
    envelope_file = check_file(envelope_file)

    print(f'Found invoice file: {invoice_file}')
    print(f'Found envelope file: {envelope_file}')

    if invoice_file is None:
        print('Error: No invoice file found')
        return
    if envelope_file is None:
        print('Error: No envelope file found')
        return

    try:
        invoice = parse_yaml_file(invoice_file)
        envelope = parse_yaml_file(envelope_file)

        print('Envelope data:')
        envelope_data = DataObject(**envelope)
        print('<--->')
        print(yaml.dump(envelope_data))
        print('</--->')

        print('Invoice data:')
        invoice_data = DataObject(**invoice)
        merge_envelope_data_into_invoice_data(invoice_data, envelope_data.Invoice)

        selected_customer = next((x for x in envelope_data.Customers if x['CustomerId'] == invoice_data.CustomerId),
                                 None)
        merge_envelope_data_into_invoice_data(invoice_data, selected_customer)

        if not hasattr(invoice_data, 'InvoiceDate'):
            invoice_data.InvoiceDate = datetime.now().date()
        else:
            invoice_data.InvoiceDate = parse_date(invoice_data.InvoiceDate)

        if not hasattr(invoice_data, 'Id'):
            invoice_data.Id = None

        if not hasattr(invoice_data, 'Positions'):
            invoice_data.Positions = []

        for position in invoice_data.Positions:
            if 'PricePerUnit' not in position or position['PricePerUnit'] is None:
                position['PricePerUnit'] = invoice_data.PricePerUnit

        invoice_data.Id = invoice_data.Id or invoice_file.stem
        print('<--->')
        print(yaml.dump(invoice_data))
        print('</--->')

    except FileNotFoundError as e:
        print(f'Error: {e}')
        return
    except yaml.YAMLError as e:
        print(f'Error: {e}')
        return
    except Exception as e:
        print(f'Error: {e}')
        return

    if not PurePath(args.template).is_absolute():
        template_dir = (Path(args.base) / args.template).resolve()
    else:
        template_dir = Path(args.template).resolve()

    generator = html_generator.HtmlTemplate(template_dir)
    template = generator.prepare_template(invoice_data, envelope_data)

    try:
        print('Generating invoice...')
        output_path = Path(args.base) / 'pdf' 
        output_path.mkdir(parents=True, exist_ok=True)
        output_path = output_path / f'{invoice_data.Id}.pdf'
        invoice_pdf = output_path.resolve()
        print(f'Invoice PDF: {invoice_pdf}')
        generator.convert_html_to_pdf(template, invoice_pdf)
    except Exception as e:
        print(f'Error: {e}')
        return


if __name__ == "__main__":
    main()
