<?php

declare(strict_types=1);

require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../ActivityLog.php';
require_once __DIR__ . '/../FileManager.php';

/**
 * TaskManager
 * 
 * Handles task CRUD, assignments, comments, and attachments
 */
class TaskManager
{
    /**
     * Get all tasks for a project
     */
    public static function getTasks(int $projectId, int $companyId, array $filters = []): array
    {
        $pdo = getPDO();
        
        $sql = 'SELECT t.*, 
                       ts.name as status_name, ts.color as status_color, ts.is_completed,
                       u.name as created_by_name,
                       (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comment_count,
                       (SELECT COUNT(*) FROM task_attachments WHERE task_id = t.id) as attachment_count
                FROM tasks t
                LEFT JOIN task_statuses ts ON t.status_id = ts.id
                LEFT JOIN users u ON t.created_by = u.id
                WHERE t.project_id = ? AND t.company_id = ?';
        
        $params = [$projectId, $companyId];
        
        if (!empty($filters['status_id'])) {
            $sql .= ' AND t.status_id = ?';
            $params[] = (int)$filters['status_id'];
        }
        
        if (!empty($filters['priority'])) {
            $sql .= ' AND t.priority = ?';
            $params[] = $filters['priority'];
        }
        
        if (!empty($filters['assigned_to'])) {
            $sql .= ' AND EXISTS (
                SELECT 1 FROM task_assignments 
                WHERE task_id = t.id AND user_id = ?
            )';
            $params[] = (int)$filters['assigned_to'];
        }
        
        if (!empty($filters['search'])) {
            $sql .= ' AND (t.title LIKE ? OR t.description LIKE ?)';
            $searchTerm = '%' . $filters['search'] . '%';
            $params[] = $searchTerm;
            $params[] = $searchTerm;
        }
        
        $sql .= ' ORDER BY t.sort_order ASC, t.created_at DESC';
        
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        
        $tasks = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
        
        // Get assignees for each task
        foreach ($tasks as &$task) {
            $task['assignees'] = self::getTaskAssignees((int)$task['id']);
        }
        
        return $tasks;
    }
    
    /**
     * Get a single task
     */
    public static function getTask(int $taskId, int $companyId): ?array
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('
            SELECT t.*, 
                   ts.name as status_name, ts.color as status_color, ts.is_completed,
                   u.name as created_by_name,
                   p.name as project_name
            FROM tasks t
            LEFT JOIN task_statuses ts ON t.status_id = ts.id
            LEFT JOIN users u ON t.created_by = u.id
            LEFT JOIN projects p ON t.project_id = p.id
            WHERE t.id = ? AND t.company_id = ?
        ');
        
        $stmt->execute([$taskId, $companyId]);
        $task = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if ($task) {
            $task['assignees'] = self::getTaskAssignees($taskId);
            $task['comments'] = self::getTaskComments($taskId);
            $task['attachments'] = self::getTaskAttachments($taskId);
        }
        
        return $task ?: null;
    }
    
    /**
     * Create a new task
     */
    public static function createTask(int $projectId, int $companyId, int $userId, array $data): int
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('
            INSERT INTO tasks (
                project_id, company_id, title, description,
                status_id, priority, due_date, estimated_hours, created_by
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        ');
        
        $stmt->execute([
            $projectId,
            $companyId,
            $data['title'],
            $data['description'] ?? null,
            $data['status_id'] ?? null,
            $data['priority'] ?? 'medium',
            $data['due_date'] ?? null,
            $data['estimated_hours'] ?? null,
            $userId
        ]);
        
        $taskId = (int)$pdo->lastInsertId();
        
        // Assign users if provided
        if (!empty($data['assignees']) && is_array($data['assignees'])) {
            foreach ($data['assignees'] as $assigneeId) {
                self::assignTask($taskId, (int)$assigneeId, $userId);
            }
        }
        
        // Log activity
        ActivityLog::log($companyId, $userId, 'task_created', 'task', $taskId, $data['title']);
        
        return $taskId;
    }
    
    /**
     * Update a task
     */
    public static function updateTask(int $taskId, int $companyId, int $userId, array $data): bool
    {
        $pdo = getPDO();
        
        $fields = [];
        $params = [];
        
        if (isset($data['title'])) {
            $fields[] = 'title = ?';
            $params[] = $data['title'];
        }
        
        if (isset($data['description'])) {
            $fields[] = 'description = ?';
            $params[] = $data['description'];
        }
        
        if (isset($data['status_id'])) {
            $fields[] = 'status_id = ?';
            $params[] = $data['status_id'] ?: null;
            
            // Check if status is completed
            if ($data['status_id']) {
                $statusStmt = $pdo->prepare('SELECT is_completed FROM task_statuses WHERE id = ?');
                $statusStmt->execute([$data['status_id']]);
                $isCompleted = $statusStmt->fetchColumn();
                
                if ($isCompleted) {
                    $fields[] = 'completed_at = NOW()';
                } else {
                    $fields[] = 'completed_at = NULL';
                }
            }
        }
        
        if (isset($data['priority'])) {
            $fields[] = 'priority = ?';
            $params[] = $data['priority'];
        }
        
        if (isset($data['due_date'])) {
            $fields[] = 'due_date = ?';
            $params[] = $data['due_date'] ?: null;
        }
        
        if (isset($data['estimated_hours'])) {
            $fields[] = 'estimated_hours = ?';
            $params[] = $data['estimated_hours'] ?: null;
        }
        
        if (isset($data['actual_hours'])) {
            $fields[] = 'actual_hours = ?';
            $params[] = $data['actual_hours'] ?: null;
        }
        
        if (empty($fields)) {
            return false;
        }
        
        $params[] = $taskId;
        $params[] = $companyId;
        
        $sql = 'UPDATE tasks SET ' . implode(', ', $fields) . ' WHERE id = ? AND company_id = ?';
        $stmt = $pdo->prepare($sql);
        $result = $stmt->execute($params);
        
        if ($result) {
            $task = self::getTask($taskId, $companyId);
            ActivityLog::log($companyId, $userId, 'task_updated', 'task', $taskId, $task['title'] ?? '');
        }
        
        return $result;
    }
    
    /**
     * Delete a task
     */
    public static function deleteTask(int $taskId, int $companyId, int $userId): bool
    {
        $pdo = getPDO();
        
        $task = self::getTask($taskId, $companyId);
        if (!$task) {
            return false;
        }
        
        // Delete attachments from filesystem
        $attachments = self::getTaskAttachments($taskId);
        foreach ($attachments as $attachment) {
            if (file_exists($attachment['file_path'])) {
                @unlink($attachment['file_path']);
            }
        }
        
        $stmt = $pdo->prepare('DELETE FROM tasks WHERE id = ? AND company_id = ?');
        $result = $stmt->execute([$taskId, $companyId]);
        
        if ($result) {
            ActivityLog::log($companyId, $userId, 'task_deleted', 'task', $taskId, $task['title']);
        }
        
        return $result;
    }
    
    /**
     * Assign a task to a user
     */
    public static function assignTask(int $taskId, int $userId, int $assignedBy): bool
    {
        $pdo = getPDO();
        
        try {
            $stmt = $pdo->prepare('
                INSERT INTO task_assignments (task_id, user_id, assigned_by)
                VALUES (?, ?, ?)
                ON DUPLICATE KEY UPDATE assigned_by = VALUES(assigned_by)
            ');
            
            return $stmt->execute([$taskId, $userId, $assignedBy]);
        } catch (PDOException $e) {
            return false;
        }
    }
    
    /**
     * Unassign a task from a user
     */
    public static function unassignTask(int $taskId, int $userId): bool
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('DELETE FROM task_assignments WHERE task_id = ? AND user_id = ?');
        return $stmt->execute([$taskId, $userId]);
    }
    
    /**
     * Get task assignees
     */
    public static function getTaskAssignees(int $taskId): array
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('
            SELECT ta.*, u.name, u.email
            FROM task_assignments ta
            JOIN users u ON ta.user_id = u.id
            WHERE ta.task_id = ?
            ORDER BY u.name ASC
        ');
        
        $stmt->execute([$taskId]);
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }
    
    /**
     * Add a comment to a task
     */
    public static function addComment(int $taskId, int $userId, string $comment): int
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('
            INSERT INTO task_comments (task_id, user_id, comment)
            VALUES (?, ?, ?)
        ');
        
        $stmt->execute([$taskId, $userId, $comment]);
        
        return (int)$pdo->lastInsertId();
    }
    
    /**
     * Get task comments
     */
    public static function getTaskComments(int $taskId): array
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('
            SELECT tc.*, u.name as user_name, u.email as user_email
            FROM task_comments tc
            JOIN users u ON tc.user_id = u.id
            WHERE tc.task_id = ?
            ORDER BY tc.created_at ASC
        ');
        
        $stmt->execute([$taskId]);
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }
    
    /**
     * Add an attachment to a task
     */
    public static function addAttachment(int $taskId, int $companyId, int $userId, array $fileData): ?int
    {
        $pdo = getPDO();
        
        // Create directory if it doesn't exist
        $uploadDir = __DIR__ . '/../../storage/companies/' . $companyId . '/project-attachments';
        if (!is_dir($uploadDir)) {
            mkdir($uploadDir, 0755, true);
        }
        
        $originalFilename = $fileData['name'];
        $extension = pathinfo($originalFilename, PATHINFO_EXTENSION);
        $filename = uniqid('task_', true) . '.' . $extension;
        $filePath = $uploadDir . '/' . $filename;
        
        if (!move_uploaded_file($fileData['tmp_name'], $filePath)) {
            return null;
        }
        
        $stmt = $pdo->prepare('
            INSERT INTO task_attachments (
                task_id, uploaded_by, filename, original_filename,
                file_path, file_size, mime_type
            ) VALUES (?, ?, ?, ?, ?, ?, ?)
        ');
        
        $stmt->execute([
            $taskId,
            $userId,
            $filename,
            $originalFilename,
            $filePath,
            $fileData['size'],
            $fileData['type']
        ]);
        
        return (int)$pdo->lastInsertId();
    }
    
    /**
     * Get task attachments
     */
    public static function getTaskAttachments(int $taskId): array
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('
            SELECT ta.*, u.name as uploaded_by_name
            FROM task_attachments ta
            JOIN users u ON ta.uploaded_by = u.id
            WHERE ta.task_id = ?
            ORDER BY ta.created_at DESC
        ');
        
        $stmt->execute([$taskId]);
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }
    
    /**
     * Delete an attachment
     */
    public static function deleteAttachment(int $attachmentId, int $companyId): bool
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('SELECT * FROM task_attachments WHERE id = ?');
        $stmt->execute([$attachmentId]);
        $attachment = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$attachment) {
            return false;
        }
        
        // Delete file
        if (file_exists($attachment['file_path'])) {
            @unlink($attachment['file_path']);
        }
        
        $stmt = $pdo->prepare('DELETE FROM task_attachments WHERE id = ?');
        return $stmt->execute([$attachmentId]);
    }
    
    /**
     * Get task statuses for a workspace
     */
    public static function getStatuses(int $companyId): array
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('
            SELECT ts.*,
                   COUNT(t.id) as task_count
            FROM task_statuses ts
            LEFT JOIN tasks t ON ts.id = t.status_id
            WHERE ts.company_id = ?
            GROUP BY ts.id
            ORDER BY ts.sort_order ASC
        ');
        
        $stmt->execute([$companyId]);
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }
    
    /**
     * Create a task status
     */
    public static function createStatus(int $companyId, array $data): int
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('
            INSERT INTO task_statuses (company_id, name, color, is_completed, sort_order)
            VALUES (?, ?, ?, ?, ?)
        ');
        
        $stmt->execute([
            $companyId,
            $data['name'],
            $data['color'] ?? '#64748B',
            $data['is_completed'] ?? false,
            $data['sort_order'] ?? 0
        ]);
        
        return (int)$pdo->lastInsertId();
    }
    
    /**
     * Get tasks for calendar view
     */
    public static function getTasksForCalendar(int $companyId, string $startDate, string $endDate): array
    {
        $pdo = getPDO();
        
        $stmt = $pdo->prepare('
            SELECT t.*, 
                   ts.name as status_name, ts.color as status_color,
                   p.name as project_name, p.id as project_id
            FROM tasks t
            LEFT JOIN task_statuses ts ON t.status_id = ts.id
            LEFT JOIN projects p ON t.project_id = p.id
            WHERE t.company_id = ? 
            AND t.due_date IS NOT NULL
            AND DATE(t.due_date) BETWEEN ? AND ?
            ORDER BY t.due_date ASC
        ');
        
        $stmt->execute([$companyId, $startDate, $endDate]);
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }
    
    /**
     * Get user's assigned tasks
     */
    public static function getUserTasks(int $userId, int $companyId, array $filters = []): array
    {
        $pdo = getPDO();
        
        $sql = 'SELECT t.*, 
                       ts.name as status_name, ts.color as status_color, ts.is_completed,
                       p.name as project_name, p.id as project_id
                FROM tasks t
                JOIN task_assignments ta ON t.id = ta.task_id
                LEFT JOIN task_statuses ts ON t.status_id = ts.id
                LEFT JOIN projects p ON t.project_id = p.id
                WHERE ta.user_id = ? AND t.company_id = ?';
        
        $params = [$userId, $companyId];
        
        if (!empty($filters['status_id'])) {
            $sql .= ' AND t.status_id = ?';
            $params[] = (int)$filters['status_id'];
        }
        
        if (!empty($filters['project_id'])) {
            $sql .= ' AND t.project_id = ?';
            $params[] = (int)$filters['project_id'];
        }
        
        $sql .= ' ORDER BY t.due_date ASC, t.created_at DESC';
        
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }
}
