package tech.nevets.sheetrender;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import spark.Request;
import spark.Response;
import spark.Route;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;

// Route: "/spreadsheetrender/:sheetId/schedule.png"
public class SheetRenderingRoute implements Route {
    private static final String URL_F = "https://docs.google.com/spreadsheets/d/e/";
    private static final String URL_B_CSV = "/pub?gid=0&single=true&output=csv";
    private static final String URL_B_HTML = "/pubhtml?gid=0&single=true";
    private static Font plainFont;
    private static Font boldFont;

    static {
        try {
            plainFont = Font.createFont(Font.TRUETYPE_FONT, SheetRenderingRoute.class.getResourceAsStream("/font.ttf")).deriveFont(Font.PLAIN, 24f);
            boldFont = Font.createFont(Font.TRUETYPE_FONT, SheetRenderingRoute.class.getResourceAsStream("/font-bold.ttf")).deriveFont(Font.PLAIN, 26f);
        } catch (FontFormatException | IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object handle(Request req, Response res) throws Exception {
        try {
            String sheetRes = getRequest(URL_F + req.params(":sheetId") + URL_B_CSV);
            String[][] csv = new String[11][8];
            String[] rows = sheetRes.split("\n");
            for (int i = 0; i < rows.length && i < 11; i++) {
                String[] column = rows[i].split(",");
                for (int j = 0; j < column.length && j < 8; j++) {
                    csv[i][j] = column[j];
                }
            }

            BufferedImage img = renderImage(csv, getColorData(req.params(":sheetId")));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(img, "png", baos);

            res.type("image/png");
            res.status(200);
            return baos.toByteArray();
        } catch (final Exception e) {
            e.printStackTrace();
            res.type("plain/text");
            res.status(404);
            return "Error!";
        }
    }

    // Box Size: 178x37
    private BufferedImage renderImage(String[][] data, Map<String, Color> colorMap) throws IOException {
        BufferedImage img = new BufferedImage(1426, 409, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = img.createGraphics();

        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        for (int r = 0; r < data.length; r++) {
            for (int c = 0; c < data[c].length; c++) {
                if (data[r][c] == null) {
                    g.setColor(Color.WHITE);
                    g.fillRect((178 * c), (37 * r), 178, 37);
                    continue;
                }

                Color color = colorMap.get(data[r][c]);
                g.setColor(color == null ? Color.WHITE : color);
                g.fillRect((178 * c), (37 * r), 178, 37);

                g.setColor(Color.BLACK);
                if (c == 0 || c == 3 || r == 0) {
                    g.setFont(boldFont);
                } else {
                    g.setFont(plainFont);
                }
                g.drawString(data[r][c], (178 * c) + 10, (37 * r) + 27);
            }
        }

        g.drawImage(ImageIO.read(this.getClass().getResource("/grid.png")), 0, 0, 1426, 409, null);

        g.dispose();
        return img;
    }

    private String getRequest(String url) {
        try (HttpClient client = HttpClient.newHttpClient()) {
            HttpRequest request = HttpRequest.newBuilder()
                    .GET()
                    .uri(URI.create(url))
                    .build();
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            if (response.headers().firstValue("Location").isPresent()) {
                return getRequest(response.headers().firstValue("Location").get());
            }
            return response.body();
        } catch (final Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }

    private Map<String, Color> getColorData(String sheetId) throws IOException {
        Map<String, Color> colorMap = new HashMap<>();
        Document doc = Jsoup.parse(getRequest(URL_F + sheetId + URL_B_HTML));
        //Document doc = Jsoup.connect(URL_F + sheetId + URL_B_HTML).get();
        Elements cells = doc.select("td[class^=s]");

        for (Element cell : cells) {
            String text = cell.text();
            Color color = getColorFromCssClass(cell.className());

            // Only add non-empty text and valid colors to the map
            if (!text.isEmpty() && color != null) {
                colorMap.put(text, color);
            }
        }
        return colorMap;
    }

    private Color getColorFromCssClass(String className) {
        return switch (className) {
            case "s1" -> Color.GREEN;
            case "s2" -> Color.YELLOW;
            case "s4" -> Color.RED;
            default -> Color.WHITE;
        };
    }
}
