<?php
declare(strict_types=1);

class AiController
{
    private static function requireProjectAccess(int $projectId): array
    {
        $db      = Database::getInstance();
        $project = $db->fetch('SELECT * FROM projects WHERE id = ?', [$projectId]);
        if (!$project) { http_response_code(404); view('errors/404', [], 'base'); exit; }

        $member = $db->fetch(
            'SELECT role FROM project_members WHERE project_id = ? AND user_id = ?',
            [$projectId, Auth::id()]
        );
        if (!$member && Auth::user()['role'] !== 'admin') {
            http_response_code(403); exit;
        }
        return $project;
    }

    public static function chat(int $projectId): void
    {
        if (!AI::isEnabled() || Auth::isAiBlockedForUser()) { Helper::redirect('/project/' . $projectId); }

        $project = self::requireProjectAccess($projectId);
        $db      = Database::getInstance();
        $userId  = Auth::id();

        $success = Helper::flash('success');
        $error   = Helper::flash('error');

        $messages = $db->fetchAll(
            'SELECT role, content, created_at FROM ai_messages
             WHERE project_id = ? AND user_id = ? ORDER BY created_at ASC',
            [$projectId, $userId]
        );

        // Parse tasks from last assistant message for potential re-display
        $lastTasks = [];
        for ($i = count($messages) - 1; $i >= 0; $i--) {
            if ($messages[$i]['role'] === 'assistant') {
                $lastTasks = AI::parseTasks($messages[$i]['content']);
                break;
            }
        }

        view('projects/ai', compact('project', 'messages', 'lastTasks', 'success', 'error'));
    }

    public static function send(int $projectId): void
    {
        header('Content-Type: application/json');
        set_time_limit(180); // prevent PHP from killing the script during slow AI responses
        if (!AI::isEnabled() || Auth::isAiBlockedForUser()) {
            echo json_encode(['error' => 'AI not enabled']); exit;
        }
        $project = self::requireProjectAccess($projectId);

        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            echo json_encode(['error' => 'Method not allowed']); exit;
        }
        if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')) {
            echo json_encode(['error' => 'Invalid CSRF']); exit;
        }

        $content = trim($_POST['content'] ?? '');
        if ($content === '' || mb_strlen($content) > 8000) {
            echo json_encode(['error' => 'Invalid input']); exit;
        }

        $db     = Database::getInstance();
        $userId = Auth::id();

        // Rate limit: max 30 user messages per hour
        $recentCount = $db->fetch(
            "SELECT COUNT(*) AS cnt FROM ai_messages
             WHERE user_id = ? AND role = 'user' AND created_at > datetime('now', '-1 hour')",
            [$userId]
        );
        if ((int)($recentCount['cnt'] ?? 0) >= 30) {
            echo json_encode(['error' => Lang::get('ai_rate_limited')]); exit;
        }

        // If previous AI call failed, an orphaned user message may sit at the end
        // of history. Remove it so the API always receives alternating messages.
        $last = $db->fetch(
            "SELECT id, role FROM ai_messages
             WHERE project_id = ? AND user_id = ? ORDER BY created_at DESC LIMIT 1",
            [$projectId, $userId]
        );
        if ($last && $last['role'] === 'user') {
            $db->execute('DELETE FROM ai_messages WHERE id = ?', [$last['id']]);
        }

        $db->execute(
            'INSERT INTO ai_messages (project_id, user_id, role, content) VALUES (?,?,?,?)',
            [$projectId, $userId, 'user', $content]
        );

        $history = $db->fetchAll(
            'SELECT role, content FROM ai_messages
             WHERE project_id = ? AND user_id = ? ORDER BY created_at ASC LIMIT 40',
            [$projectId, $userId]
        );

        $response = AI::chat(AI::buildSystemPrompt($project), $history);

        if ($response === false) {
            // Keep the user message in DB so it remains visible after a page reload.
            // The orphaned-message cleanup above handles it on the next send.
            echo json_encode(['error' => Lang::get('ai_request_failed')]); exit;
        }

        $db->execute(
            'INSERT INTO ai_messages (project_id, user_id, role, content) VALUES (?,?,?,?)',
            [$projectId, $userId, 'assistant', $response]
        );

        echo json_encode([
            'response' => $response,
            'tasks'    => AI::parseTasks($response),
        ]);
    }

    public static function clearHistory(int $projectId): void
    {
        if (!AI::isEnabled() || Auth::isAiBlockedForUser()) { Helper::redirect('/project/' . $projectId); }
        self::requireProjectAccess($projectId);
        Helper::verifyCsrf();

        Database::getInstance()->execute(
            'DELETE FROM ai_messages WHERE project_id = ? AND user_id = ?',
            [$projectId, Auth::id()]
        );
        Helper::redirect('/project/' . $projectId . '/ai');
    }

    public static function createTasks(int $projectId): void
    {
        if (!AI::isEnabled() || Auth::isAiBlockedForUser()) { Helper::redirect('/project/' . $projectId); }
        self::requireProjectAccess($projectId);
        Helper::verifyCsrf();

        $tasksJson = $_POST['tasks_json'] ?? '';
        $tasks     = json_decode($tasksJson, true);
        if (!is_array($tasks) || empty($tasks)) {
            Helper::redirect('/project/' . $projectId . '/ai', ['error' => 'Keine Aufgaben gefunden']);
        }

        $db           = Database::getInstance();
        $userId       = Auth::id();
        $defaultStatus = $db->fetch(
            'SELECT id FROM task_statuses WHERE project_id = ? ORDER BY position ASC LIMIT 1',
            [$projectId]
        );
        $statusId = $defaultStatus ? (int)$defaultStatus['id'] : null;
        $created  = 0;
        $indexToId = []; // 1-based task index → real task ID

        foreach ($tasks as $idx => $t) {
            $title = trim($t['title'] ?? '');
            if ($title === '') continue;
            $priority = in_array($t['priority'] ?? '', ['low','medium','high','urgent']) ? $t['priority'] : 'medium';
            $dueDate  = !empty($t['due_date']) ? $t['due_date'] : null;
            $desc     = trim($t['description'] ?? '') ?: null;

            $startDate = !empty($t['start_date']) ? $t['start_date'] : null;

            $taskId = (int)$db->insert(
                'INSERT INTO tasks (project_id, title, description, priority, status_id, start_date, due_date, created_by)
                 VALUES (?,?,?,?,?,?,?,?)',
                [$projectId, $title, $desc, $priority, $statusId, $startDate, $dueDate, $userId]
            );
            $indexToId[$idx + 1] = $taskId; // store 1-based index
            Helper::logActivity($userId, 'activity_task_created', $title, $projectId);
            $created++;
        }

        // Wire up predecessor/successor dependencies
        foreach ($tasks as $idx => $t) {
            $successorId = $indexToId[$idx + 1] ?? null;
            if (!$successorId) continue;
            foreach ($t['predecessors'] ?? [] as $predIdx) {
                $predecessorId = $indexToId[$predIdx] ?? null;
                if ($predecessorId && $predecessorId !== $successorId) {
                    $db->execute(
                        'INSERT OR IGNORE INTO task_dependencies (predecessor_id, successor_id) VALUES (?,?)',
                        [$predecessorId, $successorId]
                    );
                }
            }
        }

        Helper::redirect('/project/' . $projectId . '/ai', ['success' => $created . ' Aufgabe(n) erstellt']);
    }
}
