package lc.captchas;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Map;
import lc.captchas.interfaces.Challenge;
import lc.captchas.interfaces.ChallengeProvider;
import lc.misc.HelperFunctions;
import lc.misc.PngImageWriter;

public class ShadowTextCaptcha implements ChallengeProvider {

  public String getId() {
    return "ShadowTextCaptcha";
  }

  public void configure(String config) {
    // TODO: Add custom config
  }

  public Map<String, List<String>> supportedParameters() {
    return Map.of(
        "supportedLevels", List.of("easy"),
        "supportedMedia", List.of("image/png"),
        "supportedInputType", List.of("text"));
  }

  public boolean checkAnswer(String secret, String answer) {
    return answer.toLowerCase().equals(secret);
  }

  private float[] makeKernel(int size) {
    final int N = size * size;
    final float weight = 1.0f / (N);
    final float[] kernel = new float[N];
    java.util.Arrays.fill(kernel, weight);
    return kernel;
  };

  private byte[] shadowText(final int width, final int height, String text) {
    BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    final int fontHeight = (int) (height * 0.5f);
    Font font = new Font("Arial", Font.PLAIN, fontHeight);
    Graphics2D graphics2D = img.createGraphics();
    HelperFunctions.setRenderingHints(graphics2D);
    graphics2D.setPaint(Color.WHITE);
    graphics2D.fillRect(0, 0, width, height);
    graphics2D.setPaint(Color.BLACK);
    graphics2D.setFont(font);
    final var stringWidth = graphics2D.getFontMetrics().stringWidth(text);
    final var padding = (stringWidth > width) ? 0 : (width - stringWidth) / 2;
    final var scaleX = (stringWidth > width) ? width / ((double) stringWidth) : 1d;
    graphics2D.scale(scaleX, 1d);
    graphics2D.drawString(text, padding, fontHeight * 1.1f);
    graphics2D.dispose();
    final int kernelSize = (int) Math.ceil((Math.min(width, height) / 50.0));
    ConvolveOp op =
        new ConvolveOp(
            new Kernel(kernelSize, kernelSize, makeKernel(kernelSize)),
            ConvolveOp.EDGE_NO_OP,
            null);
    BufferedImage img2 = op.filter(img, null);
    Graphics2D g2d = img2.createGraphics();
    HelperFunctions.setRenderingHints(g2d);
    g2d.setPaint(Color.WHITE);
    g2d.scale(scaleX, 1d);
    g2d.setFont(font);
    g2d.drawString(text, padding - kernelSize, fontHeight * 1.1f);
    g2d.dispose();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
      PngImageWriter.write(baos, img2);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return baos.toByteArray();
  }

  public Challenge returnChallenge(String level, String size) {
    String secret = HelperFunctions.randomString(6);
    final int[] size2D = HelperFunctions.parseSize2D(size);
    final int width = size2D[0];
    final int height = size2D[1];
    return new Challenge(shadowText(width, height, secret), "image/png", secret.toLowerCase());
  }
}
