<?php
/**
 * ファイル内メタデータ（APP_VERSION / APP_CATEGORY / APP_DESCRIPTION / APP_MEMO）
 * LISTER 互換
 */
const FL_META_KEYS = [
    'APP_VERSION',
    'APP_CATEGORY',
    'APP_DESCRIPTION',
    'APP_MEMO',
];

function fl_meta_empty(): array
{
    return [
        'APP_VERSION'     => '',
        'APP_CATEGORY'    => '',
        'APP_DESCRIPTION' => '',
        'APP_MEMO'        => '',
    ];
}

function fl_meta_normalize_field(string $field): string
{
    $field = strtoupper(trim($field));

    if ($field === 'DESCRIPTION') {
        return 'APP_DESCRIPTION';
    }

    return in_array($field, FL_META_KEYS, true) ? $field : '';
}

function fl_format_version_from_mtime($mtime)
{
    return date('Y.m.d', (int) $mtime);
}

function fl_display_version(array $meta, $filename, $mtime)
{
    if ($meta['APP_VERSION'] !== '') {
        return $meta['APP_VERSION'];
    }

    $name = pathinfo($filename, PATHINFO_FILENAME);
    $parts = explode('_', $name, 2);
    $ver = isset($parts[0]) ? $parts[0] : '';

    if ($ver !== '' && preg_match('/^\d/', $ver)) {
        return $ver;
    }

    return fl_format_version_from_mtime($mtime);
}

function fl_read_meta(string $file): array
{
    $meta = fl_meta_empty();

    if (!is_file($file)) {
        return $meta;
    }

    $txt = @file_get_contents($file);

    if ($txt === false) {
        return $meta;
    }

    $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));

    if ($ext === 'php') {
        return fl_read_meta_php($txt);
    }

    if (in_array($ext, ['txt', 'md', 'log'], true)) {
        return fl_read_meta_txt($txt);
    }

    if (in_array($ext, ['html', 'htm'], true)) {
        return fl_read_meta_html($txt);
    }

    if ($ext === 'js') {
        return fl_read_meta_js($txt);
    }

    if ($ext === 'css') {
        return fl_read_meta_css($txt);
    }

    if ($ext === 'json') {
        return fl_read_meta_json($txt);
    }

    return $meta;
}

function fl_read_meta_php(string $txt): array
{
    $meta = fl_meta_empty();

    foreach (FL_META_KEYS as $key) {
        $q = preg_quote($key, '/');
        if (preg_match("/define\s*\(\s*'{$q}'\s*,\s*'((?:\\\\'|[^'])*)'\s*\)/", $txt, $m)) {
            $meta[$key] = stripcslashes($m[1]);
            continue;
        }
        if (preg_match('/define\s*\(\s*"' . $q . '"\s*,\s*"((?:\\\\"|[^"])*)"\s*\)/', $txt, $m)) {
            $meta[$key] = stripcslashes($m[1]);
        }
    }

    if ($meta['APP_DESCRIPTION'] === '') {
        foreach (['APP_Description', 'Description'] as $legacy) {
            $q = preg_quote($legacy, '/');
            if (preg_match("/define\s*\(\s*'{$q}'\s*,\s*'((?:\\\\'|[^'])*)'\s*\)/", $txt, $m)) {
                $meta['APP_DESCRIPTION'] = stripcslashes($m[1]);
                break;
            }
        }
    }

    return $meta;
}

function fl_read_meta_txt(string $txt): array
{
    $meta = fl_meta_empty();
    $keys = implode('|', FL_META_KEYS);

    foreach (preg_split('/\r?\n/', $txt) as $line) {
        if (preg_match("/^#\s*({$keys}|Description):\s*(.*)$/", $line, $m)) {
            $key = $m[1] === 'Description' ? 'APP_DESCRIPTION' : $m[1];
            $meta[$key] = $m[2];
            continue;
        }

        if (trim($line) === '') {
            continue;
        }

        break;
    }

    return $meta;
}

function fl_read_meta_html(string $txt): array
{
    $meta = fl_meta_empty();

    foreach (FL_META_KEYS as $key) {
        if (preg_match('/<!--\s*' . preg_quote($key, '/') . ':\s*(.*?)\s*-->/s', $txt, $m)) {
            $meta[$key] = trim($m[1]);
        }
    }

    if ($meta['APP_DESCRIPTION'] === '' && preg_match('/<!--\s*Description:\s*(.*?)\s*-->/s', $txt, $m)) {
        $meta['APP_DESCRIPTION'] = trim($m[1]);
    }

    return $meta;
}

function fl_read_meta_js(string $txt): array
{
    $meta = fl_meta_empty();
    $keys = implode('|', FL_META_KEYS);

    if (preg_match_all('/\/\/\s*(' . $keys . '|Description):\s*(.*)$/m', $txt, $ms, PREG_SET_ORDER)) {
        foreach ($ms as $m) {
            $key = $m[1] === 'Description' ? 'APP_DESCRIPTION' : $m[1];
            $meta[$key] = $m[2];
        }
    }

    return $meta;
}

function fl_read_meta_css(string $txt): array
{
    $meta = fl_meta_empty();

    if (preg_match('/\/\*\s*([\s\S]*?)\s*\*\//', $txt, $block)) {
        foreach (preg_split('/\r?\n/', $block[1]) as $line) {
            if (preg_match('/^\s*(APP_VERSION|APP_CATEGORY|APP_DESCRIPTION|APP_MEMO|Description):\s*(.*)$/', trim($line), $m)) {
                $key = $m[1] === 'Description' ? 'APP_DESCRIPTION' : $m[1];
                $meta[$key] = $m[2];
            }
        }
    }

    return $meta;
}

function fl_read_meta_json(string $txt): array
{
    $meta = fl_meta_empty();
    $data = json_decode($txt, true);

    if (!is_array($data)) {
        return $meta;
    }

    foreach (FL_META_KEYS as $key) {
        if (!empty($data[$key])) {
            $meta[$key] = (string) $data[$key];
        }
    }

    if ($meta['APP_DESCRIPTION'] === '' && !empty($data['Description'])) {
        $meta['APP_DESCRIPTION'] = (string) $data['Description'];
    }

    return $meta;
}

function fl_escape_php_string(string $value): string
{
    return str_replace(["\\", "'"], ["\\\\", "\\'"], $value);
}

function fl_split_txt_body(string $txt): array
{
    $meta = fl_meta_empty();
    $body = [];
    $keys = implode('|', FL_META_KEYS);

    foreach (preg_split('/\r?\n/', $txt) as $line) {
        if (preg_match("/^#\s*({$keys}|Description):\s*(.*)$/", $line, $m)) {
            $key = $m[1] === 'Description' ? 'APP_DESCRIPTION' : $m[1];
            $meta[$key] = $m[2];
            continue;
        }

        $body[] = $line;
    }

    return [$meta, ltrim(implode("\n", $body), "\n")];
}

function fl_build_txt_header(array $meta): string
{
    $lines = [];

    foreach (FL_META_KEYS as $key) {
        if ($meta[$key] !== '') {
            $lines[] = '# ' . $key . ': ' . $meta[$key];
        }
    }

    if ($lines === []) {
        return '';
    }

    return implode("\n", $lines) . "\n\n";
}
