import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TxtToCsv {

    private static final Pattern DATE_RE =
            Pattern.compile("^[A-Z][a-z]{2,8}\\s+\\d{1,2},\\s+\\d{4}$");
    private static final Pattern TIME_RE =
            Pattern.compile("^\\d{1,2}:\\d{2}\\s*[AaPp][Mm]$");
    private static final Pattern AMOUNT_RE =
            Pattern.compile("(\\d[\\d,]*\\.\\d{1,2}|\\d[\\d,]*)");
    private static final Pattern BARE_AMOUNT_LINE =
            Pattern.compile("^\\d[\\d,]*\\.\\d{1,2}$");

    // Input date formats we accept, e.g. "Sep 29, 2025" or "September 29, 2025"
    private static final DateTimeFormatter[] DATE_IN = {
            DateTimeFormatter.ofPattern("MMM d, yyyy", Locale.ENGLISH),
            DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH),
    };

    private static final String[] FIELDS = {
            "Paid To", "Transaction ID", "UTR No", "Debited From",
            "Type", "Amount", "Date", "Time"
    };

    public static void main(String[] args) throws IOException {
        if (args.length != 2) {
            System.out.println("Usage: java TxtToCsv input.txt output.csv");
            System.exit(1);
        }

        String text = Files.readString(Path.of(args[0]), StandardCharsets.UTF_8);

        List<List<String>> blocks = splitIntoBlocks(text);
        List<Map<String, String>> records = new ArrayList<>();
        for (List<String> block : blocks) {
            records.add(parseBlock(block));
        }

        StringBuilder csv = new StringBuilder();
        csv.append(String.join(",", escapeRow(FIELDS))).append("\r\n");
        for (Map<String, String> rec : records) {
            String[] row = new String[FIELDS.length];
            for (int i = 0; i < FIELDS.length; i++) {
                row[i] = rec.getOrDefault(FIELDS[i], "");
            }
            csv.append(String.join(",", escapeRow(row))).append("\r\n");
        }

        Files.writeString(Path.of(args[1]), csv.toString(), StandardCharsets.UTF_8);
        System.out.println("Wrote " + records.size() + " transaction(s) to " + args[1]);
    }

    private static List<List<String>> splitIntoBlocks(String text) {
        List<List<String>> blocks = new ArrayList<>();
        List<String> current = new ArrayList<>();

        for (String raw : text.split("\\R", -1)) {
            if (raw.strip().toLowerCase().startsWith("paid to") && !current.isEmpty()) {
                blocks.add(current);
                current = new ArrayList<>();
                current.add(raw);
            } else {
                current.add(raw);
            }
        }
        if (!current.isEmpty()) {
            blocks.add(current);
        }

        List<List<String>> result = new ArrayList<>();
        for (List<String> b : blocks) {
            boolean hasPaidTo = b.stream()
                    .anyMatch(l -> l.strip().toLowerCase().startsWith("paid to"));
            if (hasPaidTo) result.add(b);
        }
        return result;
    }

    private static Map<String, String> parseBlock(List<String> lines) {
        Map<String, String> rec = new LinkedHashMap<>();
        for (String f : FIELDS) rec.put(f, "");

        for (String raw : lines) {
            String line = raw.strip();
            if (line.isEmpty()) continue;
            String low = line.toLowerCase();

            if (low.startsWith("paid to")) {
                rec.put("Paid To", stripLeading(line, "paid to"));
                continue;
            }
            if (low.startsWith("transaction id")) {
                rec.put("Transaction ID", afterColon(line));
                continue;
            }
            if (low.startsWith("utr no")) {
                rec.put("UTR No", afterColon(line));
                continue;
            }
            if (low.startsWith("debited from")) {
                rec.put("Debited From", stripLeading(line, "debited from"));
                continue;
            }
            if (DATE_RE.matcher(line).matches()) {
                rec.put("Date", toIsoDate(line));
                continue;
            }
            if (TIME_RE.matcher(line).matches()) {
                rec.put("Time", line.toUpperCase());
                continue;
            }

            if (low.matches("^(debit|credit)\\b.*")) {
                rec.put("Type", low.startsWith("debit") ? "Debit" : "Credit");
            }

            if (rec.get("Amount").isEmpty()) {
                boolean hasMarker = low.contains("inr") || line.contains("\u20b9")
                        || low.matches(".*\\brs\\.?\\b.*");
                if (hasMarker || BARE_AMOUNT_LINE.matcher(line).matches()) {
                    Matcher m = AMOUNT_RE.matcher(line);
                    if (m.find()) {
                        rec.put("Amount", m.group(1).replace(",", ""));
                    }
                }
            }
        }
        return rec;
    }

    /** "Sep 29, 2025" -> "2025-09-29" (sortable). Returns input unchanged if unparseable. */
    private static String toIsoDate(String s) {
        for (DateTimeFormatter f : DATE_IN) {
            try {
                return LocalDate.parse(s, f).toString();
            } catch (Exception ignore) {
                // try next format
            }
        }
        return s;
    }

    private static String stripLeading(String line, String prefix) {
        String rest = line.substring(prefix.length());
        return rest.replaceAll("^[\\s:]+", "").replaceAll("[\\s:]+$", "").strip();
    }

    private static String afterColon(String line) {
        int idx = line.indexOf(':');
        return idx >= 0 ? line.substring(idx + 1).strip() : "";
    }

    private static String[] escapeRow(String[] cells) {
        String[] out = new String[cells.length];
        for (int i = 0; i < cells.length; i++) {
            String c = cells[i] == null ? "" : cells[i];
            if (c.contains(",") || c.contains("\"") || c.contains("\n") || c.contains("\r")) {
                c = "\"" + c.replace("\"", "\"\"") + "\"";
            }
            out[i] = c;
        }
        return out;
    }
}