<?php
function dictionaryTenantKey(): string
{
    $tenant = trim((string)($_REQUEST['tenant'] ?? ''), "/\\ \t\n\r\0\x0B");
    if ($tenant === '' && defined('TENANT_URL')) {
        $tenant = trim((string)TENANT_URL, "/\\ \t\n\r\0\x0B");
    }

    return preg_match('/^[A-Za-z0-9_.-]+$/', $tenant) && strpos($tenant, '..') === false ? $tenant : '';
}

function dictionaryTenantRootPath(): string
{
    $tenant = dictionaryTenantKey();
    if ($tenant === '') {
        return '';
    }

    $root = realpath(__DIR__ . '/../../../' . $tenant);
    return $root !== false ? $root : '';
}

$tenant = dictionaryTenantKey();
if ($tenant !== '' && file_exists(__DIR__ . '/../../../' . $tenant . '/config.php')) {
    require_once(__DIR__ . '/../../../' . $tenant . '/config.php');
}
if (file_exists('/config.php')) {
    require_once('/config.php');
}

function dictionaryFilePath(): string
{
    $root = dictionaryTenantRootPath();
    if ($root === '') {
        return '';
    }

    return $root . DIRECTORY_SEPARATOR . 'forms' . DIRECTORY_SEPARATOR . 'enrep_custom_words.txt';
}

function dictionaryEnsureFile(string $file): bool
{
    if ($file === '') {
        return false;
    }

    $dir = dirname($file);
    if (!is_dir($dir) && !mkdir($dir, 0775, true)) {
        return false;
    }

    if (!is_file($file) && file_put_contents($file, '', LOCK_EX) === false) {
        return false;
    }

    return is_writable($file);
}

function dictionaryReadWords(string $file): array
{
    $words = is_file($file) ? file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) : [];
    $clean = [];

    foreach ($words ?: [] as $word) {
        $word = trim((string)$word);
        if ($word !== '' && $word[0] !== '#') {
            $clean[strtolower($word)] = $word;
        }
    }

    natcasesort($clean);
    return array_values($clean);
}

function dictionaryCleanWord(string $word): string
{
    return preg_replace('/\s+/', '', trim($word));
}

function dictionaryValidWord(string $word): bool
{
    return (bool)preg_match("/^[A-Za-z][A-Za-z'\\-]{1,63}$/", $word);
}

function dictionaryWriteWords(string $file, array $words): bool
{
    $content = implode(PHP_EOL, $words);
    if ($content !== '') {
        $content .= PHP_EOL;
    }

    return file_put_contents($file, $content, LOCK_EX) !== false;
}

function dictionaryCsvOutput(string $filename, array $words): void
{
    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="' . $filename . '"');

    $out = fopen('php://output', 'wb');
    fputcsv($out, ['word']);
    foreach ($words as $word) {
        fputcsv($out, [$word]);
    }
    fclose($out);
    exit;
}

function dictionaryReadCsvWords(string $path): array
{
    $words = [];
    $invalid = [];
    $handle = fopen($path, 'rb');

    if (!$handle) {
        return ['words' => [], 'invalid' => ['Unable to read CSV file']];
    }

    $rowNumber = 0;
    $wordIndex = 0;

    while (($row = fgetcsv($handle)) !== false) {
        $rowNumber++;
        if ($rowNumber === 1) {
            $headers = array_map(function ($value) {
                return strtolower(trim((string)$value));
            }, $row);
            $found = array_search('word', $headers, true);
            if ($found !== false) {
                $wordIndex = (int)$found;
                continue;
            }
        }

        $word = dictionaryCleanWord((string)($row[$wordIndex] ?? ''));
        if ($word === '') {
            continue;
        }

        if (!dictionaryValidWord($word)) {
            $invalid[] = 'Row ' . $rowNumber . ': ' . $word;
            continue;
        }

        $words[strtolower($word)] = $word;
    }

    fclose($handle);
    natcasesort($words);

    return ['words' => array_values($words), 'invalid' => $invalid];
}

$action = (string)($_REQUEST['action'] ?? 'list');
$file = dictionaryFilePath();

if ($action === 'custom_words') {
    header('Content-Type: text/plain; charset=utf-8');
    echo is_file($file) ? (string)file_get_contents($file) : '';
    exit;
}

if (($_SESSION['usertype'] ?? '') !== 'admins') {
    header('Content-Type: application/json');
    http_response_code(403);
    echo json_encode(['status' => 'error', 'message' => 'Admin access required']);
    exit;
}

if (!dictionaryEnsureFile($file)) {
    header('Content-Type: application/json');
    http_response_code(500);
    echo json_encode(['status' => 'error', 'message' => 'Tenant dictionary is not writable']);
    exit;
}

if ($action === 'template') {
    dictionaryCsvOutput('enrep_dictionary_import_template.csv', ['LOLER', 'PUWER', 'example-term']);
}

if ($action === 'export') {
    dictionaryCsvOutput('enrep_custom_dictionary.csv', dictionaryReadWords($file));
}

header('Content-Type: application/json');

if ($action === 'list') {
    echo json_encode(['status' => 'success', 'words' => dictionaryReadWords($file)]);
    exit;
}

if ($action === 'add') {
    $word = dictionaryCleanWord((string)($_POST['word'] ?? ''));
    if (!dictionaryValidWord($word)) {
        http_response_code(400);
        echo json_encode(['status' => 'error', 'message' => 'Invalid dictionary word']);
        exit;
    }

    $words = dictionaryReadWords($file);
    $lookup = array_change_key_case(array_flip($words), CASE_LOWER);
    if (!isset($lookup[strtolower($word)])) {
        $words[] = $word;
        natcasesort($words);
        dictionaryWriteWords($file, array_values($words));
    }

    echo json_encode(['status' => 'success']);
    exit;
}

if ($action === 'delete') {
    $word = dictionaryCleanWord((string)($_POST['word'] ?? ''));
    $words = array_values(array_filter(dictionaryReadWords($file), function ($existing) use ($word) {
        return strtolower((string)$existing) !== strtolower($word);
    }));

    dictionaryWriteWords($file, $words);
    echo json_encode(['status' => 'success']);
    exit;
}

if ($action === 'import_preview') {
    if (empty($_FILES['dictionary_csv']['tmp_name']) || !is_uploaded_file($_FILES['dictionary_csv']['tmp_name'])) {
        http_response_code(400);
        echo json_encode(['status' => 'error', 'message' => 'Please choose a CSV file']);
        exit;
    }

    $parsed = dictionaryReadCsvWords($_FILES['dictionary_csv']['tmp_name']);
    $existing = dictionaryReadWords($file);
    $existingLookup = array_change_key_case(array_flip($existing), CASE_LOWER);
    $new = [];
    $collisions = [];

    foreach ($parsed['words'] as $word) {
        if (isset($existingLookup[strtolower($word)])) {
            $collisions[] = $word;
        } else {
            $new[] = $word;
        }
    }

    echo json_encode([
        'status' => 'success',
        'newWords' => $new,
        'collisions' => $collisions,
        'invalid' => $parsed['invalid'],
    ]);
    exit;
}

if ($action === 'import_commit') {
    $incoming = json_decode((string)($_POST['words'] ?? '[]'), true);
    if (!is_array($incoming)) {
        http_response_code(400);
        echo json_encode(['status' => 'error', 'message' => 'Invalid import payload']);
        exit;
    }

    $words = dictionaryReadWords($file);
    $lookup = array_change_key_case(array_flip($words), CASE_LOWER);
    $added = 0;

    foreach ($incoming as $word) {
        $word = dictionaryCleanWord((string)$word);
        if (!dictionaryValidWord($word) || isset($lookup[strtolower($word)])) {
            continue;
        }
        $lookup[strtolower($word)] = count($words);
        $words[] = $word;
        $added++;
    }

    natcasesort($words);
    dictionaryWriteWords($file, array_values($words));

    echo json_encode(['status' => 'success', 'added' => $added]);
    exit;
}

http_response_code(400);
echo json_encode(['status' => 'error', 'message' => 'Unknown dictionary action']);
