<?php
require_once dirname(__FILE__, 2).'/settings/.config.php';

readonly class ImagePreview
{
    private array $curlConfig;

    public function __construct(private \PDO $db, private string $path, array $curlConfig = [])
    {
        $this->curlConfig = $curlConfig ?: [
            CURLOPT_RETURNTRANSFER => true,  // Возврат результата в виде строки
            CURLOPT_HEADER => false, // Игнорирование заголовков ответа сервера
            CURLOPT_FOLLOWLOCATION => true,  // Автоматическое перенаправление на другие страницы
            CURLOPT_MAXREDIRS => 10,    // Максимальное количество перенаправлений
            CURLOPT_CONNECTTIMEOUT => 10,    // Время ожидания соединения с сервером (секунды)
            CURLOPT_TIMEOUT => 60,    // Время ожидания ответа от сервера (секунды)
            CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
            // CURLOPT_PROXY          => '127.0.0.1:8118'	// Опция для прокси (тор не прокатывает)
        ];
    }

    public function clean(): void
    {
        $selectStmt = $this->db->prepare('SELECT hash FROM icecast2 WHERE releaseId = :releaseId LIMIT 1');
        foreach (glob($this->path.'/*.jpg') as $file) {
            // Проверим по базе файл
            $selectStmt->execute([':releaseId' => basename($file, '.jpg')]);
            $files = $selectStmt->fetch(PDO::FETCH_ASSOC);
            // Нет записи
            if (empty($files['hash'])) {
                unlink($file);
            }
        }
    }

    public function dieIfProcessRunning(): void
    {
        // Если сервер уже выполняет задачу - запретить
        exec('ps aux | grep .cover.php', $output, $return);
        if (count($output) > 3) {
            die('Сервер занят данной командой'.PHP_EOL);
        }
    }

    public function loadImages(): void
    {
        $updateStmt = $this->db->prepare('UPDATE icecast2 SET releaseId = :releaseId WHERE hash = :hash LIMIT 1');
        // Ищем {mbid} на musicbrainz.org
        foreach ($this->db->query('SELECT * FROM icecast2 ORDER by RAND()') as $row) {
            // Путь до файла
            $cacheFile = $this->path.'/'.$row['releaseId'].'.jpg';
            // Есть ли файл
            if (is_file($cacheFile)) {
                $creationTime = filectime($cacheFile);
                $twoDaysAgo = time() - (2 * 24 * 60 * 60); // два дня в секундах
                // Старше двух дней, пропустить
                if ($creationTime > $twoDaysAgo) {
                    continue;
                }
            }
            // Разделим исполнителя и название
            [$artist, $title] = preg_split('/\s-\s/', $row['track'], 2);
            // Закодируем параметры запроса
            $encodedArtist = urlencode($artist);
            $encodedTitle = urlencode($title);
            // URL запроса {mbid}
            $url = "https://musicbrainz.org/ws/2/release/?query=artist:\"$encodedArtist\"%20release:\"$encodedTitle\"&fmt=json";
            // Притормозим запросы иначе будет 503 ошибка
            sleep(5);
            // Запуск CURL
            $ch = curl_init($url);
            // Передадим опции
            curl_setopt_array($ch, $this->curlConfig);
            // Получим ответ
            $response = curl_exec($ch);
            // Код ответа сервера
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            // Проверим на ошибки
            if (curl_errno($ch)) {
                continue;
            }
            // Если ответ положительный, продолжим
            if ($httpCode !== 200) {
                continue;
            }
            // Раскодируем ответ
            $data = json_decode($response, true, 512, \JSON_THROW_ON_ERROR);
            // Проверим на существование данных
            if (!isset($data['releases'][0]['id'])) {
                continue;
            }
            // Проверим равен ли полученный {mbid} с записанным в базе
            if ($data['releases'][0]['id'] == $row['releaseId']) {
                continue;
            }
            // Запишем или обновим данные
            $updateStmt->execute([':releaseId' => $data['releases'][0]['id'], ':hash' => $row['hash']]);
            echo $httpCode.' записан '.$data['releases'][0]['id'].' ID файла '.$row['id'];
        }
    }

    public function writeImages(): void
    {
        $updateStmt = $this->db->prepare('UPDATE icecast2 SET releaseId = NULL WHERE hash = :hash LIMIT 1');
        // Скачивание release используя {mbid}
        foreach ($this->db->query('SELECT * FROM icecast2 WHERE releaseId IS NOT NULL ORDER BY RAND()') as $row) {
            // Путь до файла
            $cacheFile = $this->path.'/'.$row['releaseId'].'.jpg';
            // Если файла нет, продолжаем
            if (is_file($cacheFile)) {
                continue;
            }
            // URL откуда будем брать cover файлы
            $url = 'https://coverartarchive.org/release/'.$row['releaseId'].'/front-250';
            // Притормозим запросы иначе будет 503 ошибка
            sleep(5);
            // Запуск CURL
            $ch = curl_init($url);
            // Передадим опции
            curl_setopt_array($ch, $this->curlConfig);
            // Получим ответ
            $response = curl_exec($ch);
            // Код ответа сервера
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            // Проверим на ошибки
            if (curl_errno($ch)) {
                continue;
            }
            // Если ответ не положительный
            if ($httpCode !== 200) {
                echo $httpCode.' удалён '.$row['releaseId'].' ID файла '.$row['id'].PHP_EOL;
                // Удалим записанный {mbid}
                $updateStmt->execute([':hash' => $row['hash']]);
            } else {
                echo $httpCode.' записан '.$row['releaseId'].' ID файла '.$row['id'].PHP_EOL;
                // Иначе запишем файл
                file_put_contents($cacheFile, $response);
            }
        }
    }
}

$obj = new ImagePreview(
    $db,
    $setup['backup'].'cover',
);

$obj->clean();
$obj->dieIfProcessRunning();
$obj->loadImages();
$obj->writeImages();
