import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class TuiSpreadsheet {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Sheet sheet = new Sheet();

        System.out.println("Commands: set, get, show, save, load, quit");
        System.out.println("Example set: set A1 42");
        System.out.println("Formula: set C1 =A1+B1");

        while (true) {
            System.out.print("> ");
            String line = scanner.nextLine().trim();
            if (line.isEmpty()) {
                continue;
            }

            String[] parts = line.split("\\s+", 3);
            String command = parts[0].toLowerCase();

            switch (command) {
                case "set":
                    if (parts.length < 3) {
                        System.out.println("Use: set CELL VALUE");
                        break;
                    }
                    sheet.set(parts[1], parts[2]);
                    break;
                case "get":
                    if (parts.length < 2) {
                        System.out.println("Use: get CELL");
                        break;
                    }
                    System.out.println(parts[1].toUpperCase() + " = " + sheet.value(parts[1]));
                    break;
                case "show":
                    sheet.show();
                    break;
                case "save":
                    if (parts.length < 2) {
                        System.out.println("Use: save FILE");
                        break;
                    }
                    sheet.save(Path.of(parts[1]));
                    break;
                case "load":
                    if (parts.length < 2) {
                        System.out.println("Use: load FILE");
                        break;
                    }
                    sheet.load(Path.of(parts[1]));
                    break;
                case "quit":
                    return;
                default:
                    System.out.println("Use: set, get, show, save, load, quit");
            }
        }
    }

    private static class Sheet {
        private final Map<String, String> cells = new HashMap<>();

        private void set(String cell, String raw) {
            String key = normalizeCell(cell);
            if (key == null) {
                System.out.println("Cell must look like A1, B2, C10...");
                return;
            }
            cells.put(key, raw.trim());
            System.out.println("Stored " + key + ".");
        }

        private String value(String cell) {
            String key = normalizeCell(cell);
            if (key == null) {
                return "#INVALID_CELL";
            }
            String raw = cells.getOrDefault(key, "");
            if (!raw.startsWith("=")) {
                return raw;
            }
            return evaluate(raw.substring(1));
        }

        private String evaluate(String expr) {
            String clean = expr.replace(" ", "");
            int plusIndex = clean.indexOf('+');
            if (plusIndex < 0) {
                return "#BAD_FORMULA";
            }
            String left = clean.substring(0, plusIndex);
            String right = clean.substring(plusIndex + 1);
            Double a = numberValue(left);
            Double b = numberValue(right);
            if (a == null || b == null) {
                return "#VALUE";
            }
            return String.valueOf(a + b);
        }

        private Double numberValue(String token) {
            try {
                return Double.parseDouble(token);
            } catch (NumberFormatException ignore) {
                String fromCell = value(token);
                try {
                    return Double.parseDouble(fromCell);
                } catch (NumberFormatException e) {
                    return null;
                }
            }
        }

        private void show() {
            if (cells.isEmpty()) {
                System.out.println("(sheet is empty)");
                return;
            }
            System.out.println("Cell | Raw | Value");
            System.out.println("------------------------");
            cells.keySet().stream().sorted().forEach(cell -> {
                String raw = cells.get(cell);
                String val = value(cell);
                System.out.println(cell + " | " + raw + " | " + val);
            });
        }

        private void save(Path file) {
            StringBuilder builder = new StringBuilder();
            cells.keySet().stream().sorted().forEach(cell -> {
                builder.append(cell)
                        .append("\t")
                        .append(cells.get(cell))
                        .append("\n");
            });
            try {
                Files.writeString(file, builder.toString());
                System.out.println("Saved " + cells.size() + " cell(s) to " + file + ".");
            } catch (IOException e) {
                System.out.println("Could not save file.");
            }
        }

        private void load(Path file) {
            if (!Files.exists(file)) {
                System.out.println("File not found.");
                return;
            }
            try {
                cells.clear();
                for (String line : Files.readAllLines(file)) {
                    String[] parts = line.split("\\t", 2);
                    if (parts.length == 2) {
                        cells.put(parts[0], parts[1]);
                    }
                }
                System.out.println("Loaded " + cells.size() + " cell(s).");
            } catch (IOException e) {
                System.out.println("Could not load file.");
            }
        }

        private String normalizeCell(String raw) {
            String cell = raw.trim().toUpperCase();
            if (cell.matches("[A-Z]+[1-9][0-9]*")) {
                return cell;
            }
            return null;
        }
    }
}