<?php

/**
 * Draft API for the future Laravel platform.
 * Isolated from download/api.php, old bot flow is not changed.
 */

header('Content-Type: application/json; charset=utf-8');

const PLATFORM_API_TOKEN = 'platform_dev_token_2026_05_21'; // TODO: move to env/config before production.
const PLATFORM_BASE_URL = 'https://a-bot.cc';
const PLATFORM_GENERATED_DIR = __DIR__ . '/generated';
const PLATFORM_GENERATED_URL = '/api/generated';

try {
    require_once __DIR__ . '/../download/DBase.php';
    require_once __DIR__ . '/../UMLyMG912T/vendor/autoload.php';
    require_once __DIR__ . '/../UMLyMG912T/autoload.php';

    new DBase();
    PlatformApi::run();
} catch (Throwable $e) {
    PlatformApi::jsonError($e->getMessage(), 500);
}

class PlatformApi
{
    public static function run()
    {
        self::checkToken();

        $action = isset($_GET['action']) ? trim((string)$_GET['action']) : '';
        if ($action === '') {
            self::jsonError('Не передан action', 400);
        }

        switch ($action) {
            case 'products':
                self::jsonSuccess(self::products());
                break;
            case 'fields':
                self::jsonSuccess(self::fields(self::requiredId()));
                break;
            case 'generate':
                self::jsonSuccess(self::generate(self::requiredId()));
                break;
            default:
                self::jsonError('Неизвестный action', 404);
        }
    }

    private static function products()
    {
        $rows = DBase::getRows(
            "SELECT ps.ID, ps.NAME_PRODUCT, ps.DESCRIPTION, ps.PRICE, ps.CURRENCY, ps.TEST,
                    ps.PATH_SCRIPT, ps.DEMO_FILE, ps.FIELDS_IN_SCRIPT, ps.FORMAT, ff.EXP,
                    fi.URL AS DEMO_FILE_URL
             FROM PROD_scripts ps
             LEFT JOIN file_formats ff ON ff.ID = ps.FORMAT
             LEFT JOIN file_id fi ON fi.ID = ps.DEMO_FILE
             WHERE ps.NAME_PRODUCT IS NOT NULL
             ORDER BY ps.ID DESC"
        );

        $items = [];
        foreach ($rows as $row) {
            $items[] = [
                'id' => (int)$row['ID'],
                'name' => $row['NAME_PRODUCT'],
                'description' => $row['DESCRIPTION'],
                'price' => (int)$row['PRICE'],
                'currency' => $row['CURRENCY'] !== null ? (int)$row['CURRENCY'] : null,
                'type' => $row['EXP'],
                'test' => $row['TEST'] !== null ? (int)$row['TEST'] : null,
                'path_script' => $row['PATH_SCRIPT'],
                'fields_in_script' => $row['FIELDS_IN_SCRIPT'] !== null ? (int)$row['FIELDS_IN_SCRIPT'] : null,
                'demo_file' => $row['DEMO_FILE'] !== null ? (int)$row['DEMO_FILE'] : null,
                'demo_file_url' => $row['DEMO_FILE_URL'],
            ];
        }

        return ['items' => $items, 'count' => count($items)];
    }

    private static function fields($productId)
    {
        self::findProduct($productId);

        $rows = DBase::getRows(
            "SELECT pvf.ID, pvf.ID_PRODUCT, pvf.NAME_FIELD, pvf.TITLE_LINE, pvf.ID_VALID_FIELD,
                    pvf.OPTIONS, pvf.OPTIONAL, pvf.VALUE_IN_SCRIPT, pvf.EXAMPLE, pvf.SIDES, pvf.SORT,
                    psv.PATH_METHOD, psv.ERROR_TEXT, psv.EXAMPLE AS VALIDATION_EXAMPLE
             FROM PROD_valid_fields pvf
             LEFT JOIN PROD_scripts_validation psv ON psv.ID = pvf.ID_VALID_FIELD
             WHERE pvf.ID_PRODUCT = ?
             ORDER BY pvf.SORT ASC, pvf.ID ASC",
            [$productId]
        );

        $items = [];
        foreach ($rows as $row) {
            $items[] = [
                'id' => (int)$row['ID'],
                'product_id' => (int)$row['ID_PRODUCT'],
                'name' => $row['NAME_FIELD'],
                'title' => $row['TITLE_LINE'],
                'sort' => (int)$row['SORT'],
                'required' => (int)$row['OPTIONAL'] !== 1,
                'example' => $row['EXAMPLE'] ?: $row['VALIDATION_EXAMPLE'],
                'validator_id' => $row['ID_VALID_FIELD'] !== null ? (int)$row['ID_VALID_FIELD'] : null,
                'validator' => $row['PATH_METHOD'],
                'error_text' => $row['ERROR_TEXT'],
                'options' => self::decodeJson($row['OPTIONS']),
                'value_in_script' => $row['VALUE_IN_SCRIPT'] !== null ? (int)$row['VALUE_IN_SCRIPT'] : null,
                'sides' => $row['SIDES'],
            ];
        }

        return ['product_id' => $productId, 'items' => $items, 'count' => count($items)];
    }

    private static function generate($productId)
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            self::jsonError('Метод generate принимает только POST', 405);
        }

        $product = self::findProduct($productId);
        if (empty($product['PATH_SCRIPT'])) {
            self::jsonError('У продукта нет PATH_SCRIPT. Генерация через платформенный API пока невозможна.', 422);
        }

        $payload = self::requestPayload();
        $fields = isset($payload['fields']) && is_array($payload['fields']) ? $payload['fields'] : $payload;
        if (!$fields || !is_array($fields)) {
            self::jsonError('Не переданы поля генерации', 400);
        }

        // TODO: on the next stage reuse the exact validation chain from NavCreateFiles::sortingAndErrors().
        $method = self::methodPath($product['PATH_SCRIPT']);
        $className = 'lib\\Controllers\\' . $method['classes'];
        if (!method_exists($className, $method['staticMethod'])) {
            self::jsonError('Не найден метод генерации: ' . $className . '::' . $method['staticMethod'], 500);
        }

        $oldCwd = getcwd();
        chdir(__DIR__ . '/../UMLyMG912T');

        $resourceDir = $product['DIR_FILES'] ?: 'PROD_files/prod-id-' . $productId;
        $result = call_user_func_array($className . '::' . $method['staticMethod'], [$fields, $resourceDir]);

        if ($oldCwd) {
            chdir($oldCwd);
        }

        if (!is_array($result) || isset($result['error']) || !isset($result['file'])) {
            self::jsonError('Скрипт генерации вернул ошибку или неверный формат результата', 500, ['raw' => $result]);
        }

        $format = $product['EXP'] ?: 'pdf';
        $fileName = 'product-' . $productId . '-' . date('Ymd-His') . '-' . bin2hex(random_bytes(4)) . '.' . $format;
        $filePath = PLATFORM_GENERATED_DIR . '/' . $fileName;

        if (!is_dir(PLATFORM_GENERATED_DIR) && !mkdir(PLATFORM_GENERATED_DIR, 0775, true)) {
            self::jsonError('Не удалось создать директорию для готовых файлов', 500);
        }

        self::saveGeneratedFile($result['file'], $filePath, $format, (int)$product['LIBRARY_CODE']);

        return [
            'product_id' => $productId,
            'file' => [
                'url' => PLATFORM_BASE_URL . PLATFORM_GENERATED_URL . '/' . $fileName,
                'path' => PLATFORM_GENERATED_URL . '/' . $fileName,
                'format' => $format,
            ],
            'note' => 'Черновая генерация без Telegram-сценария, покупки, демо и финальной валидации старого бота.',
        ];
    }

    private static function saveGeneratedFile($fileObject, $filePath, $format, $libraryCode)
    {
        if ($format === 'pdf') {
            if ((int)$libraryCode === 2 && method_exists($fileObject, 'output')) {
                file_put_contents($filePath, $fileObject->output());
                return;
            }
            if (method_exists($fileObject, 'Output')) {
                $fileObject->Output($filePath, 'F');
                return;
            }
        }

        if (method_exists($fileObject, 'writeImage')) {
            if (!$fileObject->writeImage($filePath)) {
                self::jsonError('Imagick не смог сохранить файл', 500);
            }
            return;
        }

        self::jsonError('Неизвестный объект результата генерации', 500);
    }

    private static function findProduct($productId)
    {
        $product = DBase::getRow(
            "SELECT ps.*, ff.EXP
             FROM PROD_scripts ps
             LEFT JOIN file_formats ff ON ff.ID = ps.FORMAT
             WHERE ps.ID = ?",
            [$productId]
        );

        if (!$product) {
            self::jsonError('Продукт не найден', 404);
        }

        return $product;
    }

    private static function requiredId()
    {
        $id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
        if ($id <= 0) {
            self::jsonError('Не передан корректный id продукта', 400);
        }
        return $id;
    }

    private static function requestPayload()
    {
        $raw = file_get_contents('php://input');
        if ($raw !== '') {
            $json = json_decode($raw, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($json)) {
                return $json;
            }
        }

        return $_POST;
    }

    private static function checkToken()
    {
        $token = null;
        $header = self::authorizationHeader();
        if (preg_match('/Bearer\s+(.+)/i', $header, $matches)) {
            $token = trim($matches[1]);
        }

        // Temporary fallback for manual browser/curl checks. Prefer Authorization header in production.
        if (!$token && isset($_GET['token'])) {
            $token = (string)$_GET['token'];
        }

        $expected = getenv('PLATFORM_API_TOKEN') ?: PLATFORM_API_TOKEN;
        if (!$token || !hash_equals($expected, $token)) {
            self::jsonError('Нет доступа к API', 401);
        }
    }

    private static function authorizationHeader()
    {
        foreach (['HTTP_AUTHORIZATION', 'REDIRECT_HTTP_AUTHORIZATION'] as $key) {
            if (!empty($_SERVER[$key])) return (string)$_SERVER[$key];
        }

        if (function_exists('getallheaders')) {
            foreach (getallheaders() as $name => $value) {
                if (strtolower($name) === 'authorization') return (string)$value;
            }
        }

        return '';
    }

    private static function methodPath($method)
    {
        $parts = explode('/', $method);
        if (count($parts) < 2) {
            return ['classes' => 'ValidatorsString', 'staticMethod' => $method];
        }

        $staticMethod = array_pop($parts);
        return ['classes' => implode('\\', $parts), 'staticMethod' => $staticMethod];
    }

    private static function decodeJson($value)
    {
        if ($value === null || $value === '') return null;
        $decoded = json_decode($value, true);
        return json_last_error() === JSON_ERROR_NONE ? $decoded : $value;
    }

    public static function jsonSuccess($data)
    {
        echo json_encode(['success' => true, 'data' => $data], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }

    public static function jsonError($message, $status = 400, array $extra = [])
    {
        http_response_code($status);
        echo json_encode(array_merge(['success' => false, 'error' => $message], $extra), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }
}
