#!/usr/bin/env python
"""Convert CSV from FinBee to QIF

The QIFs are produced with the intent to import them to Banktivity.

This is configured by a configuration file (~/.finbee2qif) which contains a
single section 'payer map', containing arbitrary many keys that map CSV loan
IDs to Banktivity securities.

TODO(laurynas): transactions import to Banktivity in Cleared status,
regardless of whether QIF "Cleared status" is present and with what value.
"""

import argparse
import configparser
import csv
import os
import re

CONFIG_FN = "~/.finbee2qif"
CONFIG_MAPPING_SECTION = "payer map"
FINBEE_FEE_TYPE_EN = re.compile("^Account fee for period .*$")
FINBEE_FEE_TYPE_LT = re.compile("^Sąskaitos aptarnavimo mokestis už laikotarpį .*$")


class CaseSensitiveConfigParser(configparser.ConfigParser):
    """A ConfigParser that preserves the key and value cases."""

    def optionxform(self, optionstr):
        return optionstr


def get_key(row, name1, name2, fn):
    """Return a value from CSV row using one of the key names."""
    if name1 in row:
        return row[name1]
    if name2 in row:
        return row[name2]
    raise ValueError(f"Unrecognized file format for {fn}")


PAYMENT_TO_QIF_TYPES = {
    "Dalinis išankstinis paskolos grąžinimas (trumpinant įmokų grafiką)": "Sell",
    "Deposit": "Cash",
    "Early repayment": "Sell",
    "Gauta paskolos dalis (įskaitant sut. mok. grąž.)": "Sell",
    "Gautos palūkanos": "IntInc",
    "Gautos papildomos mokėjimo palūkanos dėl vėlavimo": "IntInc",
    "Interest earned": "IntInc",
    "investor.payment_request.type.ter": "Sell",
    "Išankstinis paskolos grąžinimas (įskaitant sut. mok. grąž.)": "Sell",
    "Loan disbursal": "Buy",
    "Overdue interest earned": "IntInc",
    "Paskolos įmoka nutraukus sutartį": "Sell",
    "Pinigų išmokėjimas": "Cash",
    "Principal repaid": "Sell",
    "Priteistos lėšos": "Sell",
    "Sąskaitos papildymas": "Cash",
    "Suteikta paskola": "Buy",
    "Termination": "Sell",
}


def get_qif_investment_action(payment_type):
    """Return a QIF investment action string for a given CSV payment type
    value"""
    if FINBEE_FEE_TYPE_EN.match(payment_type):
        return "Cash"
    if FINBEE_FEE_TYPE_LT.match(payment_type):
        return "Cash"
    return PAYMENT_TO_QIF_TYPES[payment_type]


arg_parser = argparse.ArgumentParser(
    description="Convert FinBee CSV statement to QIF for importing to Banktivity."
)

arg_parser.add_argument("input", type=str, help="The input file")
arg_parser.add_argument("output", type=str, help="The output file")

args = arg_parser.parse_args()

mapping_config = CaseSensitiveConfigParser()
mapping_config.read(os.path.expanduser(CONFIG_FN))

if CONFIG_MAPPING_SECTION not in mapping_config:
    raise ValueError(
        f"Config file {CONFIG_FN} does not have " f"{CONFIG_MAPPING_SECTION} section"
    )

payer_mapping = dict(mapping_config.items(CONFIG_MAPPING_SECTION))
print(payer_mapping)

with open(args.input, newline="", encoding="utf-8-sig") as input_file, open(
    args.output, "w", encoding="utf-8"
) as output_file:
    csv_reader = csv.DictReader(input_file, delimiter=";")
    output_file.write("!Type:Invst\n")
    for csv_row in csv_reader:
        date = get_key(csv_row, "Date", "Data", args.input)
        # The last line is the total, breaking the schema
        if date in ("Total amount", "Iš viso"):
            break
        amount = get_key(csv_row, "Amount", "Suma", args.input)
        purpose = get_key(csv_row, "Purpose", "Paskirtis", args.input)
        csv_payment_type = get_key(csv_row, "Type", "Tipas", args.input)
        print(
            f"Before: Date: {date}, amount: {amount}, purpose: {purpose}, "
            f"payment_type: {csv_payment_type}"
        )

        # pylint: disable=C0103
        investment_action = get_qif_investment_action(csv_payment_type)
        # pulint: enable=C0103

        if investment_action == "Buy":
            amount = amount.strip("-")

        payer = payer_mapping[purpose]

        print(f"After: investment_action: {investment_action}, payer: {payer}")

        output_file.write(f"D{date}\n")
        output_file.write(f"N{investment_action}\n")
        output_file.write("O0.0\n")
        output_file.write(f"T{amount}\n")
        if investment_action == "Cash":
            output_file.write(f"P{payer}\n")
            output_file.write("LBank Charges:Account Charge\n")
        elif investment_action == "IntInc":
            output_file.write(f"Y{payer}\n")
            output_file.write("LInterest Income\n")
        else:
            output_file.write(f"Y{payer}\n")
        if investment_action in ("Sell", "Buy"):
            output_file.write("I1.0\n")
            output_file.write(f"Q{amount}\n")
        output_file.write("^\n")
