"""Convert text files to CSV files.

This module provides functionality to extract transaction data from
text files (converted from PDF statements) and save them as CSV files.
"""

import argparse
import os
import re
from pathlib import Path

from .utils import configure_logging, get_logger

__all__ = ["convert_csv_folder", "regex_match_transaction", "txt_to_csv"]

# Configure logging
configure_logging()
log = get_logger(__name__)


def regex_match_transaction(line: str) -> tuple[str, str, str, str] | None:
    """Check if a line matches a transaction pattern.

    Matches lines with the format: DD/MM DD/MM DESCRIPTION AMOUNT

    Args:
        line: Text line to check for transaction pattern

    Returns:
        Tuple of (posting_date, transaction_date, description, amount) if match found,
        None otherwise

    Examples:
        >>> regex_match_transaction("12/01 13/01 PURCHASE 100.00")
        ('12/01', '13/01', 'PURCHASE', '100.00')
        >>> regex_match_transaction("Invalid line")
        None
    """
    pattern = r"(\d{2}/\d{2}) (\d{2}/\d{2})(.*)\s(\d{1,3}(?:,\d{3})*\.\d{2})$"
    match = re.match(pattern, line)
    if match:
        groups = match.groups()
        return (groups[0], groups[1], groups[2], groups[3])
    return None


def regex_match_credit(line: str) -> tuple[str, str, str] | None:
    """Check if a line is a credit transaction.

    Credit transactions are marked with 'CR' suffix and are typically
    excluded from expense tracking.

    Args:
        line: Text line to check for credit pattern

    Returns:
        Tuple of (posting_date, transaction_date, description) if match found,
        None otherwise

    Examples:
        >>> regex_match_credit("12/01 13/01 PAYMENT CR")
        ('12/01', '13/01', 'PAYMENT ')
    """
    pattern = r"(\d{2}/\d{2}) (\d{2}/\d{2}) (.*)CR"
    match = re.match(pattern, line)
    if match:
        groups = match.groups()
        return (groups[0], groups[1], groups[2])
    return None


def txt_to_csv(txt_path: str, csv_path: str) -> None:
    """Convert a text file to a CSV file with transaction data.

    Extracts transaction lines from the text file and writes them to
    a CSV file. Filters out credit transactions and management charges.

    Args:
        txt_path: Path to input text file
        csv_path: Path where CSV file will be written

    Raises:
        FileNotFoundError: If text file does not exist
        OSError: If there are issues reading or writing files

    Examples:
        >>> txt_to_csv("statement.txt", "transactions.csv")
    """
    log.debug("converting_text_to_csv", txt_path=txt_path, csv_path=csv_path)

    if not os.path.exists(txt_path):
        msg = f"Text file not found: {txt_path}"
        log.error("text_file_not_found", txt_path=txt_path)
        raise FileNotFoundError(msg)

    try:
        with open(txt_path, encoding="utf-8") as txt_file:
            lines = txt_file.readlines()

        log.debug("text_file_read", txt_path=txt_path, line_count=len(lines))

        transaction_count = 0
        skipped_credit = 0
        skipped_mgmt = 0

        with open(csv_path, "w", encoding="utf-8") as csv_file:
            csv_file.write('"Posting Date","Transaction Date","Description","Amount"\n')
            for line in lines:
                matches = regex_match_transaction(line.strip())
                if matches:
                    # Skip retail management charges
                    if "RTL MGMT CHRG RATE" in line.strip().upper():
                        log.debug("skipping_management_charge", line=line.strip())
                        skipped_mgmt += 1
                        continue
                    # Skip credit transactions
                    if regex_match_credit(line):
                        log.debug("skipping_credit_transaction", line=line.strip())
                        skipped_credit += 1
                        continue

                    # Build CSV line
                    csv_line = ",".join(f'"{match.strip()}"' for match in matches)
                    csv_file.write(f"{csv_line}\n")
                    transaction_count += 1

        log.info(
            "text_converted_to_csv",
            txt_path=txt_path,
            csv_path=csv_path,
            transactions=transaction_count,
            skipped_credit=skipped_credit,
            skipped_mgmt=skipped_mgmt,
        )

    except OSError as e:
        log.error(
            "text_conversion_failed",
            txt_path=txt_path,
            error=str(e),
            error_type=type(e).__name__,
            exc_info=True,
        )
        raise


def convert_csv_folder(input_folder: str, output_folder: str) -> None:
    """Convert all text files in a folder to CSV files.

    Processes all .txt files in the input folder and creates corresponding
    CSV files in the output folder with renamed format.

    Args:
        input_folder: Folder containing text files to convert
        output_folder: Folder where CSV files will be saved

    Raises:
        FileNotFoundError: If input folder does not exist
        OSError: If output folder cannot be created or files cannot be processed

    Examples:
        >>> convert_csv_folder("/data/txt", "/data/csv")
    """
    log.info(
        "converting_csv_folder_start",
        input_folder=input_folder,
        output_folder=output_folder,
    )

    if not os.path.exists(input_folder):
        msg = f"Input folder not found: {input_folder}"
        log.error("input_folder_not_found", input_folder=input_folder)
        raise FileNotFoundError(msg)

    output_path = Path(output_folder)
    output_path.mkdir(parents=True, exist_ok=True)
    log.debug("output_folder_created", output_folder=output_folder)

    txt_files = [f for f in os.listdir(input_folder) if f.lower().endswith(".txt")]
    log.info("text_files_found", file_count=len(txt_files))

    converted_count = 0
    failed_count = 0

    for filename in txt_files:
        txt_path = os.path.join(input_folder, filename)
        # Extract date and prefix from filename (format: Prefix_YYYYMMDD.txt)
        base_name = os.path.splitext(filename)[0]
        parts = base_name.split("_")
        if len(parts) >= 2:
            csv_filename = f"{parts[-1]}-{parts[0]}.csv"
        else:
            csv_filename = f"{base_name}.csv"

        csv_path = os.path.join(output_folder, csv_filename)

        try:
            txt_to_csv(txt_path, csv_path)
            converted_count += 1
        except (FileNotFoundError, OSError) as e:
            log.error(
                "file_conversion_failed",
                filename=filename,
                error=str(e),
                error_type=type(e).__name__,
                exc_info=True,
            )
            failed_count += 1
            # Continue processing other files even if one fails
            continue

    log.info(
        "csv_folder_conversion_complete",
        total_files=len(txt_files),
        converted=converted_count,
        failed=failed_count,
    )


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Convert statement text files to CSV files"
    )
    parser.add_argument("input_folder", type=str, help="Folder containing text files")
    parser.add_argument("output_folder", type=str, help="Folder to save CSV files")
    args = parser.parse_args()
    convert_csv_folder(args.input_folder, args.output_folder)
