<?php
declare(strict_types=1);

require_once __DIR__ . '/admin_bootstrap.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/file_api_client.php';

$ADMIN_TASK_TITLE_MAX = 100;
$ADMIN_TASK_COMMENT_MAX = 2000;
$ADMIN_TASK_ATTACHMENTS_MAX = 10;
$ADMIN_TASK_ATTACHMENT_MAX_BYTES = 20 * 1024 * 1024;

$pdo = admin_get_pdo();
$auth = admin_require_auth($pdo);

$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';

function admin_task_files_table_exists(PDO $pdo): bool
{
    static $cached = null;
    if ($cached !== null) {
        return $cached;
    }

    try {
        $stmt = $pdo->prepare('SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :t');
        $stmt->execute([':t' => 'admin_task_files']);
        $cached = ((int)$stmt->fetchColumn() > 0);

        if (!$cached) {
            $pdo->exec(
                'CREATE TABLE IF NOT EXISTS admin_task_files ('
                . 'id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,'
                . 'task_id BIGINT UNSIGNED NOT NULL,'
                . 'file_name VARCHAR(255) NOT NULL,'
                . 'file_mime VARCHAR(255) NULL,'
                . 'file_size BIGINT UNSIGNED NULL,'
                . 'file_path VARCHAR(500) NOT NULL COMMENT \'Ścieżka na dysku relative to files_base_dir\','
                . 'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,'
                . 'PRIMARY KEY (id),'
                . 'KEY idx_task_id (task_id),'
                . 'KEY idx_created_at (created_at),'
                . 'CONSTRAINT fk_admin_task_files_task FOREIGN KEY (task_id) REFERENCES admin_tasks(id) ON DELETE CASCADE'
                . ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'
            );

            $stmt->execute([':t' => 'admin_task_files']);
            $cached = ((int)$stmt->fetchColumn() > 0);
        }
    } catch (Throwable $e) {
        $cached = false;
    }

    return $cached;
}

function admin_task_comments_table_exists(PDO $pdo): bool
{
    static $cached = null;
    if ($cached !== null) {
        return $cached;
    }

    try {
        $stmt = $pdo->prepare('SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :t');
        $stmt->execute([':t' => 'admin_task_comments']);
        $cached = ((int)$stmt->fetchColumn() > 0);

        if (!$cached) {
            $pdo->exec(
                'CREATE TABLE IF NOT EXISTS admin_task_comments ('
                . 'id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,'
                . 'task_id BIGINT UNSIGNED NOT NULL,'
                . 'user_id INT NOT NULL,'
                . 'username VARCHAR(100) NOT NULL,'
                . 'comment TEXT NOT NULL,'
                . 'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,'
                . 'updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,'
                . 'PRIMARY KEY (id),'
                . 'KEY idx_task_id (task_id),'
                . 'KEY idx_created_at (created_at),'
                . 'KEY idx_user_id (user_id),'
                . 'CONSTRAINT fk_admin_task_comments_task FOREIGN KEY (task_id) REFERENCES admin_tasks(id) ON DELETE CASCADE'
                . ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'
            );

            $stmt->execute([':t' => 'admin_task_comments']);
            $cached = ((int)$stmt->fetchColumn() > 0);
        }
    } catch (Throwable $e) {
        $cached = false;
    }

    return $cached;
}

function admin_task_get_comments_count_map(PDO $pdo, array $taskIds): array
{
    $map = [];
    if (empty($taskIds) || !admin_task_comments_table_exists($pdo)) {
        return $map;
    }

    $taskIds = array_values(array_unique(array_map('intval', $taskIds)));
    $taskIds = array_values(array_filter($taskIds, static fn($id) => $id > 0));
    if (empty($taskIds)) {
        return $map;
    }

    $ph = [];
    $bind = [];
    foreach ($taskIds as $i => $id) {
        $k = ':id' . $i;
        $ph[] = $k;
        $bind[$k] = $id;
    }

    $sql = 'SELECT task_id, COUNT(*) AS cnt FROM admin_task_comments WHERE task_id IN (' . implode(', ', $ph) . ') GROUP BY task_id';
    $stmt = $pdo->prepare($sql);
    foreach ($bind as $k => $v) {
        $stmt->bindValue($k, $v, PDO::PARAM_INT);
    }
    $stmt->execute();

    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    foreach ($rows as $r) {
        $taskId = (int)($r['task_id'] ?? 0);
        if ($taskId > 0) {
            $map[$taskId] = (int)($r['cnt'] ?? 0);
        }
    }

    return $map;
}

function admin_task_assert_exists(PDO $pdo, int $taskId): void
{
    $stmt = $pdo->prepare('SELECT id FROM admin_tasks WHERE id = :id LIMIT 1');
    $stmt->execute([':id' => $taskId]);
    if (!(bool)$stmt->fetchColumn()) {
        admin_json_error('Nie znaleziono notatki', 404);
    }
}

function admin_task_list_comments(PDO $pdo, int $taskId): array
{
    if (!admin_task_comments_table_exists($pdo)) {
        return [];
    }

    $stmt = $pdo->prepare(
        'SELECT id, task_id, user_id, username, comment, created_at, updated_at '
        . 'FROM admin_task_comments WHERE task_id = :task_id ORDER BY id ASC'
    );
    $stmt->execute([':task_id' => $taskId]);
    return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
}

function admin_task_detect_mime(string $tmpPath, string $originalName, string $browserMime = ''): string
{
    $browserMime = strtolower(trim(explode(';', $browserMime)[0] ?? ''));

    $detectedMime = '';
    if (function_exists('finfo_open')) {
        $fi = finfo_open(FILEINFO_MIME_TYPE);
        if ($fi) {
            $detectedMime = strtolower(trim((string)(finfo_file($fi, $tmpPath) ?: '')));
            finfo_close($fi);
        }
    }

    $ext = strtolower((string)pathinfo($originalName, PATHINFO_EXTENSION));
    $extMimeMap = [
        'md' => 'text/markdown',
        'markdown' => 'text/markdown',
        'txt' => 'text/plain',
        'pdf' => 'application/pdf',
        'zip' => 'application/zip',
        'mp4' => 'video/mp4',
        'mp3' => 'audio/mpeg',
        'wav' => 'audio/wav',
        'doc' => 'application/msword',
        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'xls' => 'application/vnd.ms-excel',
        'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    ];
    $extMime = $ext !== '' && isset($extMimeMap[$ext]) ? $extMimeMap[$ext] : '';

    foreach ([$detectedMime, $browserMime, $extMime] as $candidate) {
        if ($candidate !== '' && $candidate !== 'application/octet-stream') {
            return $candidate;
        }
    }

    return $extMime !== '' ? $extMime : ($browserMime !== '' ? $browserMime : 'application/octet-stream');
}

function admin_task_collect_uploads(int $maxFileBytes): array
{
    $uploads = [];

    $uploadErrorToMessage = static function (int $err): string {
        if ($err === UPLOAD_ERR_INI_SIZE || $err === UPLOAD_ERR_FORM_SIZE) {
            return 'Plik przekracza limit uploadu serwera PHP (sprawdź upload_max_filesize i post_max_size).';
        }
        if ($err === UPLOAD_ERR_PARTIAL) {
            return 'Plik został wysłany tylko częściowo.';
        }
        if ($err === UPLOAD_ERR_NO_TMP_DIR) {
            return 'Brak katalogu tymczasowego na serwerze.';
        }
        if ($err === UPLOAD_ERR_CANT_WRITE) {
            return 'Serwer nie może zapisać pliku na dysk.';
        }
        if ($err === UPLOAD_ERR_EXTENSION) {
            return 'Upload został zatrzymany przez rozszerzenie PHP.';
        }
        return 'Błąd uploadu pliku.';
    };

    $append = static function ($name, $type, $size, $tmpName, $error) use (&$uploads, $maxFileBytes, $uploadErrorToMessage): void {
        $err = isset($error) ? (int)$error : UPLOAD_ERR_NO_FILE;
        if ($err === UPLOAD_ERR_NO_FILE) {
            return;
        }

        if ($err !== UPLOAD_ERR_OK) {
            admin_json_error($uploadErrorToMessage($err) . ' (kod: ' . $err . ')', 422);
        }

        $actualSize = isset($size) ? (int)$size : 0;
        if ($actualSize > $maxFileBytes) {
            $mb = (int)round($maxFileBytes / 1024 / 1024);
            admin_json_error('Każdy załącznik może mieć maksymalnie ' . $mb . ' MB', 422);
        }

        $tmp = (string)($tmpName ?? '');
        if ($tmp === '' || !is_uploaded_file($tmp)) {
            admin_json_error('Nieprawidłowy upload pliku', 422);
        }

        // Wyślij plik do serwisu plików FastAPI, zapisze na dysku
        $origName = (string)($name ?? 'plik');
        $mimeType = admin_task_detect_mime($tmp, $origName, (string)($type ?? ''));
        try {
            $fileApiResult = get_file_api_client()->upload('admin_tasks', $tmp, $origName, $mimeType);
        } catch (RuntimeException $e) {
            $status = (int)$e->getCode();
            if ($status < 400 || $status > 599) {
                $status = 500;
            }
            admin_json_error('Błąd zapisu załącznika: ' . $e->getMessage(), $status);
        }

        $uploads[] = [
            'file_name' => $origName,
            'file_mime' => $mimeType,
            'file_size' => isset($size) ? (int)$size : null,
            'file_path' => (string)($fileApiResult['path'] ?? ''),
        ];
    };

    $fields = ['files', 'file'];
    foreach ($fields as $field) {
        if (empty($_FILES[$field]) || !is_array($_FILES[$field])) {
            continue;
        }

        $upload = $_FILES[$field];
        $isMulti = isset($upload['name']) && is_array($upload['name']);

        if ($isMulti) {
            $count = count($upload['name']);
            for ($i = 0; $i < $count; $i++) {
                $append(
                    $upload['name'][$i] ?? null,
                    $upload['type'][$i] ?? null,
                    $upload['size'][$i] ?? null,
                    $upload['tmp_name'][$i] ?? null,
                    $upload['error'][$i] ?? UPLOAD_ERR_NO_FILE
                );
            }
        } else {
            $append(
                $upload['name'] ?? null,
                $upload['type'] ?? null,
                $upload['size'] ?? null,
                $upload['tmp_name'] ?? null,
                $upload['error'] ?? UPLOAD_ERR_NO_FILE
            );
        }
    }

    return $uploads;
}

function admin_task_count_current_attachments(PDO $pdo, int $taskId): array
{
    $legacyCount = 0;
    $modernCount = 0;

    $stmt = $pdo->prepare('SELECT (file_name IS NOT NULL AND file_name <> \'\') AS has_file FROM admin_tasks WHERE id = :id LIMIT 1');
    $stmt->execute([':id' => $taskId]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    if ($row && (int)($row['has_file'] ?? 0) === 1) {
        $legacyCount = 1;
    }

    if (admin_task_files_table_exists($pdo)) {
        $stmt = $pdo->prepare('SELECT COUNT(*) FROM admin_task_files WHERE task_id = :id');
        $stmt->execute([':id' => $taskId]);
        $modernCount = (int)$stmt->fetchColumn();
    }

    return [
        'legacy' => $legacyCount,
        'modern' => $modernCount,
        'total' => $legacyCount + $modernCount,
    ];
}

function admin_task_parse_delete_file_ids($value): array
{
    if ($value === null) {
        return [];
    }

    if (is_string($value)) {
        $value = trim($value);
        if ($value === '') {
            return [];
        }
        $value = explode(',', $value);
    }

    if (!is_array($value)) {
        return [];
    }

    $ids = [];
    foreach ($value as $item) {
        $id = (int)$item;
        if ($id > 0) {
            $ids[] = $id;
        }
    }

    return array_values(array_unique($ids));
}

function admin_task_insert_files(PDO $pdo, int $taskId, array $uploads): void
{
    if (empty($uploads)) {
        return;
    }

    $stmt = $pdo->prepare(
        'INSERT INTO admin_task_files (task_id, file_name, file_mime, file_size, file_path) '
        . 'VALUES (:task_id, :file_name, :file_mime, :file_size, :file_path)'
    );

    foreach ($uploads as $file) {
        $stmt->bindValue(':task_id', $taskId, PDO::PARAM_INT);
        $stmt->bindValue(':file_name', (string)$file['file_name'], PDO::PARAM_STR);
        $stmt->bindValue(':file_mime', (string)$file['file_mime'], PDO::PARAM_STR);
        $stmt->bindValue(':file_size', $file['file_size'] !== null ? (int)$file['file_size'] : null, $file['file_size'] !== null ? PDO::PARAM_INT : PDO::PARAM_NULL);
        $stmt->bindValue(':file_path', (string)$file['file_path'], PDO::PARAM_STR);
        $stmt->execute();
    }
}

function admin_task_get_attachments_by_task(PDO $pdo, array $taskIds): array
{
    $map = [];
    if (empty($taskIds) || !admin_task_files_table_exists($pdo)) {
        return $map;
    }

    $taskIds = array_values(array_unique(array_map('intval', $taskIds)));
    $taskIds = array_values(array_filter($taskIds, static fn($id) => $id > 0));
    if (empty($taskIds)) {
        return $map;
    }

    $placeholders = [];
    $params = [];
    foreach ($taskIds as $i => $id) {
        $k = ':id' . $i;
        $placeholders[] = $k;
        $params[$k] = $id;
    }

    $sql = 'SELECT id, task_id, file_name, file_mime, file_size FROM admin_task_files '
        . 'WHERE task_id IN (' . implode(', ', $placeholders) . ') ORDER BY id ASC';
    $stmt = $pdo->prepare($sql);
    foreach ($params as $k => $v) {
        $stmt->bindValue($k, $v, PDO::PARAM_INT);
    }
    $stmt->execute();

    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    foreach ($rows as $r) {
        $taskId = (int)($r['task_id'] ?? 0);
        if ($taskId <= 0) {
            continue;
        }
        if (!isset($map[$taskId])) {
            $map[$taskId] = [];
        }
        $fileId = (int)($r['id'] ?? 0);
        $map[$taskId][] = [
            'id' => $fileId,
            'name' => (string)($r['file_name'] ?? ''),
            'mime' => (string)($r['file_mime'] ?? ''),
            'size' => isset($r['file_size']) ? (int)$r['file_size'] : null,
            'download_url' => '/api/admin_task_file.php?file_id=' . $fileId,
        ];
    }

    return $map;
}

if ($method === 'GET') {
    $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 50;
    $limit = max(1, min(200, $limit));

    try {
        $stmt = $pdo->prepare(
            'SELECT id, title, description, created_by, created_by_username, created_at, updated_at, '
            . 'is_done, done_at, done_by, done_by_username, '
            . '(file_name IS NOT NULL AND file_name <> \'\') AS has_file, file_name, file_mime, file_size '
            . 'FROM admin_tasks '
            . 'ORDER BY id DESC '
            . 'LIMIT :limit'
        );
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->execute();
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $taskIds = [];
        foreach ($rows as $r) {
            $taskIds[] = (int)($r['id'] ?? 0);
        }
        $attachmentsMap = admin_task_get_attachments_by_task($pdo, $taskIds);
        $commentsCountMap = admin_task_get_comments_count_map($pdo, $taskIds);

        foreach ($rows as &$r) {
            $taskId = (int)($r['id'] ?? 0);
            $attachments = $attachmentsMap[$taskId] ?? [];

            if (!empty($r['file_name'])) {
                $attachments[] = [
                    'id' => null,
                    'name' => (string)$r['file_name'],
                    'mime' => (string)($r['file_mime'] ?? ''),
                    'size' => isset($r['file_size']) ? (int)$r['file_size'] : null,
                    'download_url' => '/api/admin_task_file.php?id=' . $taskId,
                    'legacy' => true,
                ];
            }

            $r['attachments'] = $attachments;
            $r['attachments_count'] = count($attachments);
            $r['has_file'] = $r['attachments_count'] > 0;
            $r['comments_count'] = (int)($commentsCountMap[$taskId] ?? 0);

            if ($r['has_file'] && !empty($attachments[0])) {
                $r['file_name'] = (string)($attachments[0]['name'] ?? $r['file_name']);
                $r['file_mime'] = (string)($attachments[0]['mime'] ?? $r['file_mime']);
                $r['file_size'] = isset($attachments[0]['size']) ? (int)$attachments[0]['size'] : $r['file_size'];
            }

            $r['is_done'] = (bool)((int)($r['is_done'] ?? 0));
            $r['done_by'] = isset($r['done_by']) ? (int)$r['done_by'] : null;
        }
        unset($r);

        admin_json_response([
            'success' => true,
            'data' => $rows,
            'count' => count($rows),
        ]);
    } catch (Throwable $e) {
        $msg = (string)$e->getMessage();
        $sqlState = ($e instanceof PDOException) ? (string)($e->getCode() ?? '') : '';
        $isSchemaProblem = false;

        // Common MySQL/PDO signals:
        // - SQLSTATE[42S22]: Column not found (new columns not installed)
        // - SQLSTATE[42S02]: Base table or view not found
        if (stripos($msg, 'Unknown column') !== false) $isSchemaProblem = true;
        if (stripos($msg, 'Base table or view not found') !== false) $isSchemaProblem = true;
        if ($sqlState === '42S22' || $sqlState === '42S02') $isSchemaProblem = true;

        if ($isSchemaProblem) {
            admin_json_error('Baza danych nie ma jeszcze aktualnych kolumn/tabel dla notatek. Uruchom /administration/install_notes_chat.php i odśwież Dashboard.', 500);
        }

        admin_json_error('Błąd pobierania notatek', 500);
    }
}

if ($method === 'POST') {
    $contentType = (string)($_SERVER['CONTENT_TYPE'] ?? '');

    // 1) JSON actions: update/delete/toggle_done
    if (stripos($contentType, 'application/json') !== false) {
        $body = admin_read_json_body();
        $action = isset($body['action']) ? (string)$body['action'] : '';
        $id = isset($body['id']) ? (int)$body['id'] : 0;
        $taskId = isset($body['task_id']) ? (int)$body['task_id'] : 0;
        $commentId = isset($body['comment_id']) ? (int)$body['comment_id'] : 0;

        if ($action === '') {
            admin_json_error('Nieprawidłowe żądanie (action)', 422);
        }

        if (in_array($action, ['delete', 'toggle_done', 'update'], true) && $id <= 0) {
            admin_json_error('Nieprawidłowe żądanie (id)', 422);
        }
        if (in_array($action, ['list_comments', 'add_comment'], true) && $taskId <= 0) {
            admin_json_error('Nieprawidłowe żądanie (task_id)', 422);
        }
        if ($action === 'delete_comment' && $commentId <= 0) {
            admin_json_error('Nieprawidłowe żądanie (comment_id)', 422);
        }

        try {
            if ($action === 'delete') {
                $stmt = $pdo->prepare('DELETE FROM admin_tasks WHERE id = :id');
                $stmt->execute([':id' => $id]);
                admin_json_response(['success' => true]);
            }

            if ($action === 'toggle_done') {
                $stmt = $pdo->prepare('SELECT is_done FROM admin_tasks WHERE id = :id');
                $stmt->execute([':id' => $id]);
                $cur = $stmt->fetch(PDO::FETCH_ASSOC);
                if (!$cur) {
                    admin_json_error('Nie znaleziono notatki', 404);
                }

                $currentDone = (bool)((int)($cur['is_done'] ?? 0));
                $desired = null;
                if (array_key_exists('is_done', $body)) {
                    $desired = (bool)$body['is_done'];
                }
                $newDone = $desired !== null ? $desired : !$currentDone;

                if ($newDone) {
                    $up = $pdo->prepare(
                        'UPDATE admin_tasks '
                        . 'SET is_done = 1, done_at = CURRENT_TIMESTAMP, done_by = :uid, done_by_username = :u '
                        . 'WHERE id = :id'
                    );
                    $up->execute([
                        ':uid' => (int)$auth['user_id'],
                        ':u' => (string)$auth['username'],
                        ':id' => $id,
                    ]);
                } else {
                    $up = $pdo->prepare(
                        'UPDATE admin_tasks '
                        . 'SET is_done = 0, done_at = NULL, done_by = NULL, done_by_username = NULL '
                        . 'WHERE id = :id'
                    );
                    $up->execute([':id' => $id]);
                }

                admin_json_response(['success' => true, 'is_done' => (bool)$newDone]);
            }

            if ($action === 'update') {
                $stmt = $pdo->prepare('SELECT title, description FROM admin_tasks WHERE id = :id');
                $stmt->execute([':id' => $id]);
                $cur = $stmt->fetch(PDO::FETCH_ASSOC);
                if (!$cur) {
                    admin_json_error('Nie znaleziono notatki', 404);
                }

                $title = array_key_exists('title', $body) ? trim((string)$body['title']) : (string)($cur['title'] ?? '');
                $description = array_key_exists('description', $body) ? trim((string)$body['description']) : (string)($cur['description'] ?? '');

                if ($title === '') {
                    admin_json_error('Tytuł jest wymagany', 422);
                }
                if (mb_strlen($title) > $ADMIN_TASK_TITLE_MAX) {
                    admin_json_error('Tytuł jest zbyt długi (max ' . $ADMIN_TASK_TITLE_MAX . ' znaków)', 422);
                }

                $up = $pdo->prepare('UPDATE admin_tasks SET title = :title, description = :description WHERE id = :id');
                $up->bindValue(':title', $title, PDO::PARAM_STR);
                $up->bindValue(':description', $description !== '' ? $description : null, $description !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL);
                $up->bindValue(':id', $id, PDO::PARAM_INT);
                $up->execute();
                admin_json_response(['success' => true]);
            }

            if ($action === 'list_comments') {
                admin_task_assert_exists($pdo, $taskId);
                $comments = admin_task_list_comments($pdo, $taskId);
                admin_json_response(['success' => true, 'data' => $comments]);
            }

            if ($action === 'add_comment') {
                admin_task_assert_exists($pdo, $taskId);
                $comment = trim((string)($body['comment'] ?? ''));
                if ($comment === '') {
                    admin_json_error('Treść komentarza jest wymagana', 422);
                }
                if (mb_strlen($comment) > $ADMIN_TASK_COMMENT_MAX) {
                    admin_json_error('Komentarz jest zbyt długi (max ' . $ADMIN_TASK_COMMENT_MAX . ' znaków)', 422);
                }

                if (!admin_task_comments_table_exists($pdo)) {
                    admin_json_error('Brak tabeli komentarzy tasków', 500);
                }

                $ins = $pdo->prepare(
                    'INSERT INTO admin_task_comments (task_id, user_id, username, comment) '
                    . 'VALUES (:task_id, :user_id, :username, :comment)'
                );
                $ins->execute([
                    ':task_id' => $taskId,
                    ':user_id' => (int)$auth['user_id'],
                    ':username' => (string)$auth['username'],
                    ':comment' => $comment,
                ]);

                admin_json_response(['success' => true, 'id' => (int)$pdo->lastInsertId()], 201);
            }

            if ($action === 'delete_comment') {
                if (!admin_task_comments_table_exists($pdo)) {
                    admin_json_error('Brak tabeli komentarzy tasków', 500);
                }

                $del = $pdo->prepare('DELETE FROM admin_task_comments WHERE id = :id');
                $del->execute([':id' => $commentId]);
                admin_json_response(['success' => true]);
            }

            admin_json_error('Nieznana akcja', 422);
        } catch (Throwable $e) {
            $msg = (string)$e->getMessage();
            $sqlState = ($e instanceof PDOException) ? (string)($e->getCode() ?? '') : '';
            $isSchemaProblem = false;
            if (stripos($msg, 'Unknown column') !== false) $isSchemaProblem = true;
            if (stripos($msg, 'Base table or view not found') !== false) $isSchemaProblem = true;
            if ($sqlState === '42S22' || $sqlState === '42S02') $isSchemaProblem = true;
            if ($isSchemaProblem) {
                admin_json_error('Baza danych nie ma jeszcze aktualnych kolumn/tabel dla notatek. Uruchom /administration/install_notes_chat.php i spróbuj ponownie.', 500);
            }
            admin_json_error('Błąd operacji notatek', 500);
        }
    }

    // 2) multipart/form-data: create OR update (with optional file)
    $action = isset($_POST['action']) ? (string)$_POST['action'] : '';
    $id = isset($_POST['id']) ? (int)$_POST['id'] : 0;

    $title = isset($_POST['title']) ? trim((string)$_POST['title']) : '';
    $description = isset($_POST['description']) ? trim((string)$_POST['description']) : '';
    $clearFile = isset($_POST['clear_file']) ? (bool)((int)$_POST['clear_file']) : false;
    $deleteFileIds = admin_task_parse_delete_file_ids($_POST['delete_file_ids'] ?? null);

    $newUploads = admin_task_collect_uploads($ADMIN_TASK_ATTACHMENT_MAX_BYTES);
    $hasNewUpload = !empty($newUploads);
    $hasFilesTable = admin_task_files_table_exists($pdo);

    if (count($newUploads) > $ADMIN_TASK_ATTACHMENTS_MAX) {
        admin_json_error('Maksymalnie ' . $ADMIN_TASK_ATTACHMENTS_MAX . ' załączników na raz', 422);
    }

    if (!$hasFilesTable && ($hasNewUpload || !empty($deleteFileIds))) {
        admin_json_error('Obsługa załączników tasków wymaga aktualizacji bazy. Uruchom /administration/install_notes_chat.php i spróbuj ponownie.', 500);
    }

    try {
        if ($action === 'update') {
            if ($id <= 0) {
                admin_json_error('Brak id do edycji', 422);
            }

            $stmt = $pdo->prepare('SELECT title, description, file_name FROM admin_tasks WHERE id = :id');
            $stmt->execute([':id' => $id]);
            $cur = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$cur) {
                admin_json_error('Nie znaleziono notatki', 404);
            }

            $newTitle = $title !== '' ? $title : (string)($cur['title'] ?? '');
            $newDesc = array_key_exists('description', $_POST) ? $description : (string)($cur['description'] ?? '');

            if ($newTitle === '') {
                admin_json_error('Tytuł jest wymagany', 422);
            }
            if (mb_strlen($newTitle) > $ADMIN_TASK_TITLE_MAX) {
                admin_json_error('Tytuł jest zbyt długi (max ' . $ADMIN_TASK_TITLE_MAX . ' znaków)', 422);
            }

            if ($hasFilesTable) {
                $counts = admin_task_count_current_attachments($pdo, $id);

                $deleteModernCount = 0;
                if (!empty($deleteFileIds)) {
                    $ph = [];
                    $bind = [':task_id' => $id];
                    foreach ($deleteFileIds as $idx => $fid) {
                        $k = ':fid' . $idx;
                        $ph[] = $k;
                        $bind[$k] = (int)$fid;
                    }
                    $cntSql = 'SELECT COUNT(*) FROM admin_task_files WHERE task_id = :task_id AND id IN (' . implode(', ', $ph) . ')';
                    $cntStmt = $pdo->prepare($cntSql);
                    foreach ($bind as $k => $v) {
                        $cntStmt->bindValue($k, $v, PDO::PARAM_INT);
                    }
                    $cntStmt->execute();
                    $deleteModernCount = (int)$cntStmt->fetchColumn();
                }

                $legacyAfter = $clearFile ? 0 : ($counts['legacy'] > 0 ? 1 : 0);
                $modernAfter = max(0, $counts['modern'] - $deleteModernCount) + count($newUploads);
                $totalAfter = $legacyAfter + $modernAfter;

                if ($totalAfter > $ADMIN_TASK_ATTACHMENTS_MAX) {
                    admin_json_error('Task może mieć maksymalnie ' . $ADMIN_TASK_ATTACHMENTS_MAX . ' załączników', 422);
                }
            }

            $pdo->beginTransaction();
            try {
                $fields = ['title = :title', 'description = :description'];
                $params = [
                    ':title' => $newTitle,
                    ':description' => $newDesc !== '' ? $newDesc : null,
                    ':id' => $id,
                ];

                if ($clearFile) {
                    // Usuń ewentualny legacy plik z dysku
                    try {
                        $cfRow = $pdo->query('SELECT file_path FROM admin_tasks WHERE id = ' . (int)$id . ' LIMIT 1')->fetch(PDO::FETCH_ASSOC);
                        if (!empty($cfRow['file_path'])) {
                            get_file_api_client()->deleteFile(dirname((string)$cfRow['file_path']), basename((string)$cfRow['file_path']));
                        }
                    } catch (Throwable $ignored) { }

                    $fields[] = 'file_name = NULL';
                    $fields[] = 'file_mime = NULL';
                    $fields[] = 'file_size = NULL';
                    $fields[] = 'file_path = NULL';
                } elseif (!$hasFilesTable && $hasNewUpload) {
                    $legacyFile = $newUploads[0];
                    $fields[] = 'file_name = :file_name';
                    $fields[] = 'file_mime = :file_mime';
                    $fields[] = 'file_size = :file_size';
                    $fields[] = 'file_path = :file_path';
                    $params[':file_name'] = $legacyFile['file_name'];
                    $params[':file_mime'] = $legacyFile['file_mime'];
                    $params[':file_size'] = $legacyFile['file_size'];
                    $params[':file_path'] = $legacyFile['file_path'];
                }

                $sql = 'UPDATE admin_tasks SET ' . implode(', ', $fields) . ' WHERE id = :id';
                $up = $pdo->prepare($sql);
                $up->bindValue(':title', (string)$params[':title'], PDO::PARAM_STR);
                $up->bindValue(':description', $params[':description'], $params[':description'] !== null ? PDO::PARAM_STR : PDO::PARAM_NULL);
                $up->bindValue(':id', (int)$params[':id'], PDO::PARAM_INT);
                if (array_key_exists(':file_name', $params)) {
                    $up->bindValue(':file_name', (string)$params[':file_name'], PDO::PARAM_STR);
                    $up->bindValue(':file_mime', (string)$params[':file_mime'], PDO::PARAM_STR);
                    $up->bindValue(':file_size', $params[':file_size'] !== null ? (int)$params[':file_size'] : null, $params[':file_size'] !== null ? PDO::PARAM_INT : PDO::PARAM_NULL);
                    $up->bindValue(':file_path', (string)$params[':file_path'], PDO::PARAM_STR);
                }
                $up->execute();

                if ($hasFilesTable) {
                    if (!empty($deleteFileIds)) {
                        $ph = [];
                        $bind = [':task_id' => $id];
                        foreach ($deleteFileIds as $idx => $fid) {
                            $k = ':fid' . $idx;
                            $ph[] = $k;
                            $bind[$k] = (int)$fid;
                        }

                        // Pobierz ścieżki do usunięcia z dysku przed DELETE
                        $pathSql = 'SELECT file_path FROM admin_task_files WHERE task_id = :task_id AND id IN (' . implode(', ', $ph) . ') AND file_path IS NOT NULL';
                        $pathStmt = $pdo->prepare($pathSql);
                        foreach ($bind as $k => $v) {
                            $pathStmt->bindValue($k, $v, PDO::PARAM_INT);
                        }
                        $pathStmt->execute();
                        $pathsToDelete = $pathStmt->fetchAll(PDO::FETCH_COLUMN);

                        $delSome = $pdo->prepare('DELETE FROM admin_task_files WHERE task_id = :task_id AND id IN (' . implode(', ', $ph) . ')');
                        foreach ($bind as $k => $v) {
                            $delSome->bindValue($k, $v, PDO::PARAM_INT);
                        }
                        $delSome->execute();

                        // Usuń pliki z dysku po pomyślnym DELETE z bazy
                        foreach ($pathsToDelete as $fp) {
                            try {
                                get_file_api_client()->deleteFile(dirname((string)$fp), basename((string)$fp));
                            } catch (Throwable $ignored) { }
                        }
                    }

                    if ($hasNewUpload) {
                        admin_task_insert_files($pdo, $id, $newUploads);
                    }
                }

                $pdo->commit();
            } catch (Throwable $e) {
                $pdo->rollBack();
                throw $e;
            }

            admin_json_response(['success' => true]);
        }

        // create
        if ($title === '') {
            admin_json_error('Tytuł jest wymagany', 422);
        }

        if (mb_strlen($title) > $ADMIN_TASK_TITLE_MAX) {
            admin_json_error('Tytuł jest zbyt długi (max ' . $ADMIN_TASK_TITLE_MAX . ' znaków)', 422);
        }

        if ($hasFilesTable && count($newUploads) > $ADMIN_TASK_ATTACHMENTS_MAX) {
            admin_json_error('Task może mieć maksymalnie ' . $ADMIN_TASK_ATTACHMENTS_MAX . ' załączników', 422);
        }

        $pdo->beginTransaction();
        try {
            if ($hasFilesTable) {
                $stmt = $pdo->prepare(
                    'INSERT INTO admin_tasks (title, description, created_by, created_by_username) '
                    . 'VALUES (:title, :description, :created_by, :created_by_username)'
                );
                $stmt->bindValue(':title', $title, PDO::PARAM_STR);
                $stmt->bindValue(':description', $description !== '' ? $description : null, $description !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL);
                $stmt->bindValue(':created_by', (int)$auth['user_id'], PDO::PARAM_INT);
                $stmt->bindValue(':created_by_username', (string)$auth['username'], PDO::PARAM_STR);
                $stmt->execute();

                $newId = (int)$pdo->lastInsertId();
                if ($hasNewUpload) {
                    admin_task_insert_files($pdo, $newId, $newUploads);
                }
            } else {
                $legacyFile = $hasNewUpload ? $newUploads[0] : null;

                $stmt = $pdo->prepare(
                    'INSERT INTO admin_tasks (title, description, file_name, file_mime, file_size, file_path, created_by, created_by_username) '
                    . 'VALUES (:title, :description, :file_name, :file_mime, :file_size, :file_path, :created_by, :created_by_username)'
                );

                $stmt->bindValue(':title', $title, PDO::PARAM_STR);
                $stmt->bindValue(':description', $description !== '' ? $description : null, $description !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL);
                $stmt->bindValue(':file_name', $legacyFile['file_name'] ?? null, isset($legacyFile['file_name']) ? PDO::PARAM_STR : PDO::PARAM_NULL);
                $stmt->bindValue(':file_mime', $legacyFile['file_mime'] ?? null, isset($legacyFile['file_mime']) ? PDO::PARAM_STR : PDO::PARAM_NULL);
                $stmt->bindValue(':file_size', $legacyFile['file_size'] ?? null, isset($legacyFile['file_size']) ? PDO::PARAM_INT : PDO::PARAM_NULL);
                $stmt->bindValue(':file_path', $legacyFile !== null ? (string)($legacyFile['file_path'] ?? '') : null, $legacyFile !== null ? PDO::PARAM_STR : PDO::PARAM_NULL);

                $stmt->bindValue(':created_by', (int)$auth['user_id'], PDO::PARAM_INT);
                $stmt->bindValue(':created_by_username', (string)$auth['username'], PDO::PARAM_STR);
                $stmt->execute();

                $newId = (int)$pdo->lastInsertId();
            }

            $pdo->commit();
        } catch (Throwable $e) {
            $pdo->rollBack();
            throw $e;
        }

        admin_json_response(['success' => true, 'id' => $newId], 201);
    } catch (Throwable $e) {
        $msg = (string)$e->getMessage();
        $sqlState = ($e instanceof PDOException) ? (string)($e->getCode() ?? '') : '';
        $isSchemaProblem = false;
        if (stripos($msg, 'Unknown column') !== false) $isSchemaProblem = true;
        if (stripos($msg, 'Base table or view not found') !== false) $isSchemaProblem = true;
        if ($sqlState === '42S22' || $sqlState === '42S02') $isSchemaProblem = true;
        if ($isSchemaProblem) {
            admin_json_error('Baza danych nie ma jeszcze aktualnych kolumn/tabel dla notatek. Uruchom /administration/install_notes_chat.php i spróbuj ponownie.', 500);
        }
        admin_json_error('Błąd zapisu notatki', 500);
    }
}

admin_json_error('Metoda niedozwolona', 405);
