<?php
// Enable error reporting
error_reporting(E_ALL);
ini_set('display_errors', 1);  // Show errors for debugging
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/php_errors.log');

// Session is already started in auth.php

// Function to send JSON response
function sendJsonResponse($data, $statusCode = 200) {
    http_response_code($statusCode);
    header('Content-Type: application/json');
    echo json_encode($data);
    exit;
}

// Set JSON header for all responses
header('Content-Type: application/json');

// Check if this is a direct access (for debugging)
$isDirectAccess = !isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 
                 (empty($_SERVER['HTTP_ACCEPT']) || strpos($_SERVER['HTTP_ACCEPT'], 'application/json') === false);

if ($isDirectAccess) {
    // For direct access, show a simple message
    echo json_encode([
        'success' => false,
        'message' => 'This endpoint only accepts AJAX requests',
        'debug' => [
            'is_ajax' => false,
            'request_method' => $_SERVER['REQUEST_METHOD'] ?? 'N/A',
            'content_type' => $_SERVER['CONTENT_TYPE'] ?? 'N/A'
        ]
    ]);
    exit;
}

// Normal request handling - ensure we have a valid session
require_once __DIR__ . '/includes/auth.php';

// Check if the request is POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    sendJsonResponse(['success' => false, 'message' => 'Method not allowed'], 405);
}

// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
    sendJsonResponse(['success' => false, 'message' => 'Not authenticated'], 401);
}

// Validate required fields
if (!isset($_FILES['audio']) || !isset($_POST['task_id'])) {
    sendJsonResponse([
        'success' => false, 
        'message' => 'Missing required fields',
        'debug' => [
            'files' => array_keys($_FILES),
            'post' => array_keys($_POST)
        ]
    ], 400);
}

$userId = $_SESSION['user_id'];
$taskId = (int)$_POST['task_id'];
$audioFile = $_FILES['audio'];

// Log the received file data for debugging
error_log('Received file upload: ' . print_r($audioFile, true));

// Validate file upload
if ($audioFile['error'] !== UPLOAD_ERR_OK) {
    $errorMessages = [
        UPLOAD_ERR_INI_SIZE => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
        UPLOAD_ERR_FORM_SIZE => 'The uploaded file exceeds the MAX_FILE_SIZE directive',
        UPLOAD_ERR_PARTIAL => 'The uploaded file was only partially uploaded',
        UPLOAD_ERR_NO_FILE => 'No file was uploaded',
        UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder',
        UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk',
        UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the file upload',
    ];
    
    $errorMessage = $errorMessages[$audioFile['error']] ?? 'Unknown upload error';
    error_log("File upload error: $errorMessage");
    
    http_response_code(400);
    echo json_encode([
        'success' => false, 
        'message' => $errorMessage,
        'file_error' => $audioFile['error']
    ]);
    exit;
}

// Set up upload directory
$uploadDir = __DIR__ . '/uploads/recordings/' . $userId . '/';

// Create user directory if it doesn't exist
if (!file_exists($uploadDir)) {
    if (!mkdir($uploadDir, 0755, true) && !is_dir($uploadDir)) {
        error_log('Failed to create directory: ' . $uploadDir);
        sendJsonResponse(['success' => false, 'message' => 'Failed to create upload directory'], 500);
    }
}

// Get file extension from the uploaded file's name
$fileName = preg_replace('/[^a-zA-Z0-9\._-]/', '', basename($audioFile['name']));
$fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));

// Force .wav extension
$newFileName = 'user_' . $userId . '_' . time() . '.wav';
$uploadFile = $uploadDir . $newFileName;
$relativePath = 'uploads/recordings/' . $userId . '/' . $newFileName;

// Only allow WAV files
$allowedExtensions = ['wav'];
if (!in_array($fileExt, $allowedExtensions, true)) {
    error_log('Invalid file extension: ' . $fileExt);
    sendJsonResponse(['success' => false, 'message' => 'Only WAV files are accepted. Please record again.'], 400);
}

// First try with finfo
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = $fileInfo ? finfo_file($fileInfo, $audioFile['tmp_name']) : '';
if ($fileInfo) finfo_close($fileInfo);

// If finfo fails, try with mime_content_type
if (!$mimeType && function_exists('mime_content_type')) {
    $mimeType = mime_content_type($audioFile['tmp_name']);
}

// Log the detected MIME type for debugging
error_log("Detected MIME type: " . $mimeType);

// Only allow WAV MIME type
$allowedMimeTypes = [
    'audio/wav',
    'audio/x-wav',
    'audio/wave'
];

// Check if the MIME type is allowed
$isValidType = false;
foreach ($allowedMimeTypes as $type) {
    if (strpos($mimeType, $type) === 0) {
        $isValidType = true;
        break;
    }
}

if (!$isValidType) {
    error_log("Invalid file type: $mimeType. Allowed types: " . implode(', ', $allowedMimeTypes));
    sendJsonResponse([
        'success' => false, 
        'message' => 'Invalid file type: ' . $mimeType,
        'allowed_types' => $allowedMimeTypes
    ], 400);
}

// Create uploads directory if it doesn't exist
$uploadBase = __DIR__ . '/uploads/';
$uploadDir = $uploadBase . 'recordings/' . $userId . '/';

// Ensure base uploads directory exists
if (!file_exists($uploadDir)) {
    if (!mkdir($uploadDir, 0755, true)) {
        error_log("Failed to create upload directory: $uploadDir");
        http_response_code(500);
        echo json_encode(['success' => false, 'message' => 'Failed to create upload directory']);
        exit;
    }
}

// Move the uploaded file to the target directory
if (!move_uploaded_file($audioFile['tmp_name'], $uploadDir . $newFileName)) {
    error_log("Failed to move uploaded file to: $uploadDir$newFileName");
    http_response_code(500);
    echo json_encode(['success' => false, 'message' => 'Failed to save recording']);
    exit;
}

$uploadFile = $uploadDir . $newFileName;

// Set proper permissions
chmod($uploadFile, 0644);

// Get file size
$fileSize = filesize($uploadFile);

// Default values for audio metadata
$duration = 0;
$sampleRate = 0;
$channels = 0;

// Try to get WAV header information first
if ($fileExt === 'wav' && function_exists('fopen') && function_exists('unpack')) {
    try {
        $wav = fopen($uploadFile, 'rb');
        $header = fread($wav, 44); // WAV header is 44 bytes
        if (strlen($header) >= 44) {
            $data = unpack('VChunkID/VChunkSize/VFormat/VSubchunk1ID/VSubchunk1Size/vAudioFormat/vNumChannels/VSampleRate/VByteRate/vBlockAlign/vBitsPerSample', $header);
            if (isset($data['SampleRate'])) {
                $sampleRate = $data['SampleRate'];
                $channels = $data['NumChannels'];
                
                // Calculate duration if we can get the file size
                if ($fileSize > 0) {
                    $dataSize = $fileSize - 44; // Subtract header size
                    $bytesPerSecond = $sampleRate * $channels * ($data['BitsPerSample'] / 8);
                    if ($bytesPerSecond > 0) {
                        $duration = $dataSize / $bytesPerSecond;
                    }
                }
            }
            fclose($wav);
        }
    } catch (Exception $e) {
        error_log("Error reading WAV file: " . $e->getMessage());
    }
}

// Fallback to ffmpeg if available and WAV parsing didn't work
if (($duration <= 0 || $sampleRate <= 0) && function_exists('exec')) {
    $ffmpegPath = shell_exec('which ffmpeg 2>/dev/null');
    $ffmpegPath = $ffmpegPath ? trim($ffmpegPath) : '';
    if (!empty($ffmpegPath) && is_executable($ffmpegPath)) {
        $output = [];
        $returnVar = 0;
        exec("ffmpeg -i " . escapeshellarg($uploadFile) . " 2>&1", $output, $returnVar);
    
        if ($returnVar === 0) {
            $output = implode("\n", $output);
            
            // Extract duration
            if (preg_match('/Duration: (\d+):(\d+):(\d+)\.(\d+)/', $output, $matches)) {
                $duration = $matches[1] * 3600 + $matches[2] * 60 + $matches[3] + ($matches[4] / 100);
            }
            
            // Extract audio stream info
            if (preg_match('/Audio:.* (\d+) Hz, (mono|stereo)/i', $output, $matches)) {
                $sampleRate = (int)$matches[1];
                $channels = strtolower($matches[2]) === 'stereo' ? 2 : 1;
            } elseif (preg_match('/Audio:.*? (\d+) Hz/', $output, $matches)) {
                $sampleRate = (int)$matches[1];
            }
        }
    }
}

try {
    $pdo = getDBConnection();
    
    // Start transaction
    $pdo->beginTransaction();
    
    try {
        // First, check if the task exists
        $stmt = $pdo->prepare("SELECT id FROM tasks WHERE id = ?");
        $stmt->execute([$taskId]);
        if (!$stmt->fetch()) {
            throw new Exception('Invalid task ID');
        }
        
        // Check which column name exists in the recordings table
        $columnCheck = $pdo->query("
            SELECT 
                (SELECT COUNT(*) FROM information_schema.COLUMNS 
                 WHERE TABLE_SCHEMA = DATABASE() 
                 AND TABLE_NAME = 'recordings' 
                 AND COLUMN_NAME = 'filepath') as has_filepath,
                (SELECT COUNT(*) FROM information_schema.COLUMNS 
                 WHERE TABLE_SCHEMA = DATABASE() 
                 AND TABLE_NAME = 'recordings' 
                 AND COLUMN_NAME = 'file_path') as has_file_path
        ")->fetch(PDO::FETCH_ASSOC);
        
        $pathColumn = $columnCheck['has_filepath'] > 0 ? 'filepath' : 'file_path';
        
        // Insert recording with all required fields (auto-approved)
        $stmt = $pdo->prepare("
            INSERT INTO recordings (
                user_id, task_id, filename, $pathColumn, 
                duration, sample_rate, channels, size_bytes,
                status, created_at
            ) VALUES (
                :user_id, :task_id, :filename, :filepath,
                :duration, :sample_rate, :channels, :size_bytes,
                'approved', NOW()
            )
        ");
        
        $stmt->execute([
            ':user_id' => $userId,
            ':task_id' => $taskId,
            ':filename' => $newFileName, // Use $newFileName instead of undefined $filename
            ':filepath' => $relativePath,
            ':duration' => round($duration, 2), // Round to 2 decimal places
            ':sample_rate' => $sampleRate,
            ':channels' => $channels,
            ':size_bytes' => $fileSize
        ]);
        $recordingId = $pdo->lastInsertId();
    
        // Update task status and stats in a single operation
        $taskUpdated = false;
        try {
            // First check if task is assigned and for today
            $checkStmt = $pdo->prepare("
                SELECT id FROM user_tasks 
                WHERE user_id = ? 
                AND task_id = ? 
                AND status = 'assigned'
                AND DATE(assigned_date) = CURDATE()
            ");
            $checkStmt->execute([$userId, $taskId]);
            $taskExists = $checkStmt->fetch(PDO::FETCH_ASSOC);
            
            if ($taskExists) {
                // Update the task status
                $stmt = $pdo->prepare("
                    UPDATE user_tasks 
                    SET status = 'completed',
                        completed_at = NOW()
                    WHERE user_id = ? 
                    AND task_id = ? 
                    AND status = 'assigned'
                    AND DATE(assigned_date) = CURDATE()
                ");
                $stmt->execute([$userId, $taskId]);
                $taskUpdated = $stmt->rowCount() > 0;
                
                // Log for debugging
                error_log("Task completion attempt - User: $userId, Task: $taskId, Updated: " . ($taskUpdated ? 'YES' : 'NO'));
                
                // If this was a new completion, update stats
                if ($taskUpdated) {
                    // Check which columns exist in user_stats
                    $columnCheck = $pdo->query("
                        SELECT 
                            (SELECT COUNT(*) FROM information_schema.COLUMNS 
                             WHERE TABLE_SCHEMA = DATABASE() 
                             AND TABLE_NAME = 'user_stats' 
                             AND COLUMN_NAME = 'last_updated') as has_last_updated,
                            (SELECT COUNT(*) FROM information_schema.COLUMNS 
                             WHERE TABLE_SCHEMA = DATABASE() 
                             AND TABLE_NAME = 'user_stats' 
                             AND COLUMN_NAME = 'last_participation') as has_last_participation
                    ")->fetch(PDO::FETCH_ASSOC);
                    
                    if ($columnCheck['has_last_updated'] > 0) {
                        // Use last_updated column
                        $stmt = $pdo->prepare("
                            INSERT INTO user_stats (user_id, points, today_completed, last_updated, last_participation)
                            VALUES (?, 10, 1, NOW(), CURDATE())
                            ON DUPLICATE KEY UPDATE 
                                points = points + 10,
                                today_completed = IF(DATE(last_updated) = CURDATE(), today_completed + 1, 1),
                                last_updated = NOW(),
                                last_participation = CURDATE()
                        ");
                    } else {
                        // Fall back to last_participation only
                        $stmt = $pdo->prepare("
                            INSERT INTO user_stats (user_id, points, today_completed, last_participation)
                            VALUES (?, 10, 1, CURDATE())
                            ON DUPLICATE KEY UPDATE 
                                points = points + 10,
                                today_completed = IF(DATE(last_participation) = CURDATE(), today_completed + 1, 1),
                                last_participation = CURDATE()
                        ");
                    }
                    $stmt->execute([$userId]);
                }
            }
        } catch (Exception $e) {
            error_log("Error updating task status: " . $e->getMessage());
            throw $e;
        }
        
        // Commit transaction
        $pdo->commit();
        
        // Get updated task progress for the response
        $progressStmt = $pdo->prepare("
            SELECT 
                COUNT(*) as total_tasks,
                SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed_tasks
            FROM user_tasks 
            WHERE user_id = ? 
            AND DATE(assigned_date) = CURDATE()
        ");
        $progressStmt->execute([$userId]);
        $progress = $progressStmt->fetch(PDO::FETCH_ASSOC);
        
        // Check if all tasks are now completed and update streak if needed
        $completedTasks = (int)($progress['completed_tasks'] ?? 0);
        $totalTasks = (int)($progress['total_tasks'] ?? 0);
        
        if ($completedTasks > 0 && $completedTasks === $totalTasks) {
            // All tasks completed! Check if we need to update the streak
            try {
                $streakStmt = $pdo->prepare("
                    SELECT consecutive_days, streak_updated_date
                    FROM user_stats 
                    WHERE user_id = ?
                ");
                $streakStmt->execute([$userId]);
                $streakData = $streakStmt->fetch(PDO::FETCH_ASSOC);
                
                $currentStreak = (int)($streakData['consecutive_days'] ?? 0);
                $streakUpdatedDate = $streakData['streak_updated_date'] ?? null;
                
                // Only update streak if we haven't already updated it today
                if ($streakUpdatedDate !== date('Y-m-d')) {
                    $newStreak = 1; // Default to 1
                    
                    // Check if yesterday's date (consecutive days)
                    $yesterday = date('Y-m-d', strtotime('-1 day'));
                    if ($streakUpdatedDate === $yesterday) {
                        $newStreak = $currentStreak + 1; // Increment streak
                    }
                    
                    error_log("Updating streak from $currentStreak to $newStreak for user $userId");
                    
                    $updateStreakStmt = $pdo->prepare("
                        UPDATE user_stats 
                        SET consecutive_days = ?,
                            streak_updated_date = CURDATE()
                        WHERE user_id = ?
                    ");
                    $updateStreakStmt->execute([$newStreak, $userId]);
                }
            } catch (Exception $e) {
                // Log error but don't fail the request
                error_log("Streak update error: " . $e->getMessage());
            }
        }
        
        // Get next task index (first uncompleted task or last task if all completed)
        $nextTaskStmt = $pdo->prepare("
            SELECT MIN(ut.id) as next_task_id
            FROM user_tasks ut
            WHERE ut.user_id = ? 
            AND ut.status = 'assigned'
            AND DATE(ut.assigned_date) = CURDATE()
        ");
        $nextTaskStmt->execute([$userId]);
        $nextTask = $nextTaskStmt->fetch(PDO::FETCH_ASSOC);
        
        // If no uncompleted tasks, get the last task
        if (empty($nextTask['next_task_id'])) {
            $nextTaskStmt = $pdo->prepare("
                SELECT id as next_task_id
                FROM user_tasks
                WHERE user_id = ? 
                AND DATE(assigned_date) = CURDATE()
                ORDER BY id DESC
                LIMIT 1
            ");
            $nextTaskStmt->execute([$userId]);
            $nextTask = $nextTaskStmt->fetch(PDO::FETCH_ASSOC);
        }
        
        $response = [
            'success' => true,
            'message' => 'Recording saved successfully',
            'recording_id' => $recordingId,
            'filepath' => $relativePath,
            'task_completed' => $taskUpdated,
            'progress' => [
                'completed' => (int)($progress['completed_tasks'] ?? 0),
                'total' => (int)($progress['total_tasks'] ?? 0),
                'next_task_id' => $nextTask['next_task_id'] ?? null
            ]
        ];
        
        // Only send the response once
        echo json_encode($response);
        exit;
        
    } catch (Exception $e) {
        $pdo->rollBack();
        throw $e;
    }
    
} catch (PDOException $e) {
    // Rollback transaction on error
    if (isset($pdo) && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    
    // Delete the uploaded file if database operation failed
    if (isset($uploadFile) && file_exists($uploadFile)) {
        unlink($uploadFile);
    }
    
    error_log("Database error: " . $e->getMessage());
    http_response_code(500);
    echo json_encode([
        'success' => false, 
        'message' => 'Database error',
        'error' => $e->getMessage()
    ]);
}
