package de.unitrier.st.uap.w25.tram;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

public final class Main {
    private static final Logger log = LogManager.getLogger(Main.class);

    private Main() {}

    static void main(String[] argv) {
        if (argv.length < 1) {
            System.err.println("Usage:");
            System.err.println("  java -jar tram.jar <tramFile> [--debug] [--stack [v1,v2,...]]");
            System.exit(1);
        }

        String tramPath = argv[0];
        boolean debug = false;
        String stackArg = null;

        // Parse arguments
        for (int i = 1; i < argv.length; i++) {
            switch (argv[i]) {
                case "--debug" -> debug = true;
                case "--stack" -> {
                    if (i + 1 < argv.length) {
                        stackArg = argv[++i];
                    } else {
                        System.err.println("Missing stack argument after --stack");
                        System.exit(2);
                    }
                }
                default -> {
                    System.err.println("Unknown argument: " + argv[i]);
                    System.exit(3);
                }
            }
        }

        // Verify .tram file
        Path tramFile = Path.of(tramPath);
        if (!Files.exists(tramFile)) {
            System.err.println("File not found: " + tramPath);
            System.exit(4);
        }

        // Parse optional stack
        Integer[] stack = parseStack(stackArg);

        // Load TRAM code
        Instruction[] code = Assembler.readTRAMCode(tramPath);

        // Execute and print console output
        Logger logger = LogManager.getLogger(Main.class);
        AbstractMachine tram = debug ?  new LoggedMachine(code, stack) : new AbstractMachine(code, stack);
        logger.trace("Start execution...");
        tram.execute();
        logger.trace("Finished execution.");
        logger.trace("Final STACK: {}", tram.stackStr());
    }

    // Parse "[1,2,3]" or "1,2,3"
    private static Integer[] parseStack(String stackArg) {
        if (stackArg == null || stackArg.isBlank()) return new Integer[]{};
        String trimmed = stackArg.trim();
        if (trimmed.startsWith("[") && trimmed.endsWith("]"))
            trimmed = trimmed.substring(1, trimmed.length() - 1);
        if (trimmed.isBlank()) return new Integer[]{};

        String[] parts = trimmed.split(",");
        List<Integer> list = new ArrayList<>();
        for (String p : parts) {
            try {
                list.add(Integer.parseInt(p.trim()));
            } catch (NumberFormatException e) {
                System.err.println("Invalid stack element: " + p);
                System.exit(6);
            }
        }
        return list.toArray(new Integer[0]);
    }
}