<?php declare(strict_types = 1);

namespace MailPoet\Captcha;

if (!defined('ABSPATH')) exit;


use MailPoet\Config\Env;
use MailPoet\Util\Headers;
use MailPoetVendor\Gregwar\Captcha\CaptchaBuilder;

class CaptchaRenderer {
  const DEFAULT_WIDTH = 220;
  const DEFAULT_HEIGHT = 60;

  private CaptchaPhrase $phrase;

  public function __construct(
    CaptchaPhrase $phrase
  ) {
    $this->phrase = $phrase;
  }

  public function isSupported(): bool {
    return extension_loaded('gd') && function_exists('imagettftext');
  }

  public function renderAudio(string $sessionId): void {
    $audioPath = Env::$assetsPath . '/audio/';
    $phrase = $this->getPhrase($sessionId);

    $files = [];
    foreach (str_split($phrase) as $character) {
      $file = $audioPath . strtolower($character) . '.mp3';
      if (!file_exists($file)) {
        throw new \RuntimeException("File not found.");
      }
      $files[] = $file;
    }

    Headers::setNoCacheHeaders();
    header('Content-Type: audio/mpeg');
    foreach ($files as $file) {
      readfile($file);
    }
  }

  public function renderImage(string $sessionId, $width = null, $height = null): void {
    if (!$this->isSupported()) {
      return;
    }

    $width = (isset($width) && $width > 0) ? intval($width) : self::DEFAULT_WIDTH;
    $height = (isset($height) && $height > 0) ? intval($height) : self::DEFAULT_HEIGHT;

    $fontNumbers = array_merge(range(0, 3), [5]); // skip font #4
    $fontNumber = $fontNumbers[mt_rand(0, count($fontNumbers) - 1)];

    $reflector = new \ReflectionClass(CaptchaBuilder::class);
    $captchaDirectory = dirname((string)$reflector->getFileName());
    $font = $captchaDirectory . '/Font/captcha' . $fontNumber . '.ttf';

    $phrase = $this->getPhrase($sessionId);
    $builder = CaptchaBuilder::create($phrase)
      ->setBackgroundColor(255, 255, 255)
      ->setTextColor(1, 1, 1)
      ->setMaxBehindLines(0)
      ->build($width, $height, $font);

    Headers::setNoCacheHeaders();
    header('Content-Type: image/jpeg');
    $builder->output();
  }

  public function refreshPhrase(string $sessionId): string {
    return $this->phrase->createPhrase($sessionId);
  }

  private function getPhrase(string $sessionId): string {
    $phrase = $this->phrase->getPhrase($sessionId);
    if (!$phrase) {
      throw new \RuntimeException("No CAPTCHA phrase was generated.");
    }
    return $phrase;
  }
}
