<?php
/**
 * analyze-file-risk.php - SQLite Compatible PII Risk Analysis Engine
 */

require_once '../config.php';
requireLogin();

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

// Only accept POST requests
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['success' => false, 'message' => 'Method not allowed']);
    exit;
}

// Check if file was uploaded
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
    $errorMessage = 'File upload failed. ';
    if (isset($_FILES['file']['error'])) {
        switch ($_FILES['file']['error']) {
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                $errorMessage .= 'File too large. Maximum size is 10MB.';
                break;
            case UPLOAD_ERR_NO_FILE:
                $errorMessage .= 'No file was uploaded.';
                break;
            default:
                $errorMessage .= 'Please try again.';
        }
    }
    echo json_encode(['success' => false, 'message' => $errorMessage]);
    exit;
}

$file = $_FILES['file'];

// Validate file size (10MB max)
$maxSize = 10 * 1024 * 1024;
if ($file['size'] > $maxSize) {
    echo json_encode(['success' => false, 'message' => 'File size exceeds 10MB limit']);
    exit;
}

// Validate file type
$allowedExtensions = ['txt', 'csv', 'pdf', 'docx', 'xlsx'];
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));

if (!in_array($extension, $allowedExtensions)) {
    echo json_encode(['success' => false, 'message' => 'Unsupported file type. Please upload TXT, CSV, PDF, DOCX, or XLSX files.']);
    exit;
}

// Create upload directory if not exists
$uploadDir = __DIR__ . '/../uploads/risk_analysis/';
if (!file_exists($uploadDir)) {
    mkdir($uploadDir, 0755, true);
}

// Generate unique filename
$safeFilename = preg_replace('/[^a-zA-Z0-9._-]/', '_', $file['name']);
$uniqueId = time() . '_' . rand(1000, 9999);
$storedFilename = $uniqueId . '_' . $safeFilename;
$filePath = $uploadDir . $storedFilename;

// Move uploaded file
if (!move_uploaded_file($file['tmp_name'], $filePath)) {
    echo json_encode(['success' => false, 'message' => 'Failed to save file']);
    exit;
}

// Extract text content from file
$fileContent = extractFileContentSimplified($filePath, $extension);

if ($fileContent === false || empty(trim($fileContent))) {
    unlink($filePath);
    if ($extension === 'pdf') {
        echo json_encode(['success' => false, 'message' => 'Could not extract text from PDF. The file may be scanned/image PDF or password protected. Try uploading a text-based PDF.']);
    } else {
        echo json_encode(['success' => false, 'message' => 'Could not extract text content from file. The file may be empty or corrupted.']);
    }
    exit;
}

// Analyze for PII
$analysisResult = analyzePII($fileContent);

// Calculate risk score
$riskScore = calculateRiskScore($analysisResult);

// Determine risk level
$riskLevel = getRiskLevel($riskScore);

// Save analysis to database
$userId = $_SESSION['user_id'];
$org = getUserOrganization($userId);
$organizationId = $org ? $org['id'] : null;

$pdo = getDBConnection();

try {
    // Create table if not exists (SQLite compatible)
    createRiskAnalysisTableIfNotExists($pdo);
    
    $detectedPiiTypes = json_encode($analysisResult['detected_types']);
    $detectedPiiCount = json_encode($analysisResult['type_counts']);
    
    // SQLite compatible INSERT (no NOW() function)
    $stmt = $pdo->prepare("
        INSERT INTO file_risk_analyses (
            user_id, organization_id, original_filename, original_filepath, 
            file_size, file_type, risk_score, risk_level,
            detected_pii_types, detected_pii_count, total_sensitive_fields,
            status, ip_address, user_agent, created_at
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'analyzed', ?, ?, datetime('now'))
    ");
    
    $stmt->execute([
        $userId,
        $organizationId,
        $file['name'],
        $filePath,
        $file['size'],
        $extension,
        $riskScore,
        $riskLevel,
        $detectedPiiTypes,
        $detectedPiiCount,
        $analysisResult['total_matches'],
        $_SERVER['REMOTE_ADDR'],
        $_SERVER['HTTP_USER_AGENT'] ?? null
    ]);
    
    $fileId = $pdo->lastInsertId();
    
    // Return results
    echo json_encode([
        'success' => true,
        'file_id' => $fileId,
        'risk_score' => $riskScore,
        'risk_level' => $riskLevel,
        'detected_pii' => $analysisResult['detected_types'],
        'total_sensitive_fields' => $analysisResult['total_matches'],
        'message' => getRecommendationMessage($riskScore, $analysisResult)
    ]);
    
} catch (Exception $e) {
    error_log("File analysis save error: " . $e->getMessage());
    // Clean up file on error
    if (file_exists($filePath)) {
        unlink($filePath);
    }
    echo json_encode(['success' => false, 'message' => 'Database error: ' . $e->getMessage()]);
}
exit;

/**
 * Create table if not exists (SQLite compatible)
 */
function createRiskAnalysisTableIfNotExists($pdo) {
    $sql = "CREATE TABLE IF NOT EXISTS file_risk_analyses (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        user_id INTEGER NOT NULL,
        organization_id INTEGER,
        original_filename VARCHAR(255) NOT NULL,
        original_filepath VARCHAR(500),
        anonymized_filepath VARCHAR(500),
        file_size INTEGER DEFAULT 0,
        file_type VARCHAR(100),
        risk_score INTEGER DEFAULT 0,
        risk_level VARCHAR(20) DEFAULT 'Low',
        detected_pii_types TEXT,
        detected_pii_count TEXT,
        total_sensitive_fields INTEGER DEFAULT 0,
        anonymization_performed INTEGER DEFAULT 0,
        watermark_applied INTEGER DEFAULT 0,
        download_count INTEGER DEFAULT 0,
        status VARCHAR(20) DEFAULT 'uploaded',
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        ip_address VARCHAR(45),
        user_agent TEXT
    )";
    
    $pdo->exec($sql);
}

/**
 * Extract text content reliably
 */
function extractFileContentSimplified($filePath, $extension) {
    $content = '';
    
    try {
        switch ($extension) {
            case 'txt':
            case 'csv':
                $content = file_get_contents($filePath);
                break;
                
            case 'pdf':
                $content = extractPDFSimple($filePath);
                break;
                
            case 'docx':
                $content = extractDOCXSimple($filePath);
                break;
                
            case 'xlsx':
                $content = extractXLSXSimple($filePath);
                break;
                
            default:
                $content = file_get_contents($filePath);
        }
    } catch (Exception $e) {
        error_log("Extraction error: " . $e->getMessage());
        return false;
    }
    
    // Clean up the content
    if ($content) {
        // Remove excessive whitespace
        $content = preg_replace('/\s+/', ' ', $content);
        $content = trim($content);
    }
    
    return $content;
}

/**
 * PDF extraction - Works with most text-based PDFs
 */
function extractPDFSimple($filePath) {
    $content = '';
    
    // Read raw PDF content
    $pdfContent = file_get_contents($filePath);
    
    if (empty($pdfContent)) {
        return false;
    }
    
    // Method 1: Extract text between BT and ET blocks (standard text PDFs)
    if (preg_match_all('/BT(.*?)ET/s', $pdfContent, $textBlocks)) {
        foreach ($textBlocks[1] as $block) {
            // Extract text from Tj operator
            if (preg_match_all('/\((.*?)\)\s*Tj/s', $block, $matches)) {
                foreach ($matches[1] as $match) {
                    // Decode PDF escaped characters
                    $match = str_replace(['\\(', '\\)', '\\n', '\\r'], ['(', ')', "\n", "\r"], $match);
                    $content .= $match . ' ';
                }
            }
            // Handle TJ arrays
            if (preg_match_all('/\[(.*?)\]\s*TJ/s', $block, $arrayMatches)) {
                foreach ($arrayMatches[1] as $arrayContent) {
                    if (preg_match_all('/\((.*?)\)/', $arrayContent, $textParts)) {
                        foreach ($textParts[1] as $part) {
                            $part = str_replace(['\\(', '\\)', '\\n', '\\r'], ['(', ')', "\n", "\r"], $part);
                            $content .= $part . ' ';
                        }
                    }
                }
            }
        }
    }
    
    // Method 2: If no text found, try extracting from stream objects
    if (empty($content)) {
        if (preg_match_all('/stream(.*?)endstream/s', $pdfContent, $streams)) {
            foreach ($streams[1] as $stream) {
                // Try to decode if it's FlateDecoded
                $decoded = @gzuncompress($stream);
                if ($decoded === false) {
                    $decoded = $stream;
                }
                // Extract readable text (ASCII printable characters)
                if (preg_match_all('/[a-zA-Z0-9\s\.,;:!?\'"()-]{4,}/', $decoded, $textMatches)) {
                    $content .= implode(' ', $textMatches[0]) . ' ';
                }
            }
        }
    }
    
    // Method 3: Simple pattern extraction for any readable text
    if (empty($content)) {
        // Remove binary garbage and keep only readable text
        $text = preg_replace('/[^\x20-\x7E\x0A\x0D]/', ' ', $pdfContent);
        $text = preg_replace('/\s+/', ' ', $text);
        
        // Extract words (3+ characters)
        if (preg_match_all('/[A-Za-z]{3,}/', $text, $words)) {
            $content = implode(' ', $words[0]);
        }
    }
    
    // Clean up PDF specific markers
    $content = preg_replace('/\[\d+\]/', '', $content);
    $content = preg_replace('/\/[A-Za-z]+/', '', $content);
    $content = preg_replace('/\s+/', ' ', $content);
    
    return trim($content);
}

/**
 * DOCX extraction
 */
function extractDOCXSimple($filePath) {
    if (!class_exists('ZipArchive')) {
        return file_get_contents($filePath);
    }
    
    $zip = new ZipArchive();
    $content = '';
    
    if ($zip->open($filePath) === true) {
        $xmlContent = $zip->getFromName('word/document.xml');
        if ($xmlContent) {
            // Remove XML tags
            $content = strip_tags($xmlContent);
            // Decode HTML entities
            $content = html_entity_decode($content, ENT_QUOTES, 'UTF-8');
        }
        $zip->close();
    }
    
    return $content;
}

/**
 * XLSX extraction
 */
function extractXLSXSimple($filePath) {
    if (!class_exists('ZipArchive')) {
        return file_get_contents($filePath);
    }
    
    $zip = new ZipArchive();
    $content = '';
    
    if ($zip->open($filePath) === true) {
        // Try sharedStrings.xml first
        $xmlContent = $zip->getFromName('xl/sharedStrings.xml');
        if ($xmlContent) {
            preg_match_all('/<t[^>]*>(.*?)<\/t>/', $xmlContent, $matches);
            if (!empty($matches[1])) {
                $content = implode(' ', $matches[1]);
            }
        }
        
        // If no content, try sheet files
        if (empty($content)) {
            for ($i = 0; $i < $zip->numFiles; $i++) {
                $filename = $zip->getNameIndex($i);
                if (preg_match('/xl\/worksheets\/sheet\d+\.xml/', $filename)) {
                    $sheetXml = $zip->getFromName($filename);
                    if ($sheetXml) {
                        preg_match_all('/<v>(.*?)<\/v>/', $sheetXml, $matches);
                        if (!empty($matches[1])) {
                            $content .= implode(' ', $matches[1]) . ' ';
                        }
                    }
                }
            }
        }
        $zip->close();
    }
    
    return $content;
}

/**
 * PII Detection Patterns
 */
function analyzePII($content) {
    $detectedTypes = [];
    $typeCounts = [];
    $totalMatches = 0;
    
    // Email addresses
    preg_match_all('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/', $content, $emailMatches);
    if (count($emailMatches[0]) > 0) {
        $detectedTypes[] = 'email';
        $typeCounts['email'] = count($emailMatches[0]);
        $totalMatches += count($emailMatches[0]);
    }
    
    // Kenyan phone numbers
    preg_match_all('/(?:\+254|0)[17][0-9]{8}/', $content, $phoneMatches);
    if (count($phoneMatches[0]) > 0) {
        $detectedTypes[] = 'phone';
        $typeCounts['phone'] = count($phoneMatches[0]);
        $totalMatches += count($phoneMatches[0]);
    }
    
    // ID Numbers (8 digits)
    preg_match_all('/\b[0-9]{8}\b/', $content, $idMatches);
    if (count($idMatches[0]) > 0) {
        $detectedTypes[] = 'id_number';
        $typeCounts['id_number'] = count($idMatches[0]);
        $totalMatches += count($idMatches[0]);
    }
    
    // KRA PIN (A123456789B format)
    preg_match_all('/[A-Z][0-9]{9}[A-Z]/', $content, $kraMatches);
    if (count($kraMatches[0]) > 0) {
        $detectedTypes[] = 'kra_pin';
        $typeCounts['kra_pin'] = count($kraMatches[0]);
        $totalMatches += count($kraMatches[0]);
    }
    
    // Bank Account (10-16 digits)
    preg_match_all('/\b[0-9]{10,16}\b/', $content, $bankMatches);
    if (count($bankMatches[0]) > 0) {
        $detectedTypes[] = 'bank_account';
        $typeCounts['bank_account'] = count($bankMatches[0]);
        $totalMatches += count($bankMatches[0]);
    }
    
    $detectedTypes = array_unique($detectedTypes);
    
    return [
        'detected_types' => $detectedTypes,
        'type_counts' => $typeCounts,
        'total_matches' => $totalMatches
    ];
}

/**
 * Calculate Risk Score
 */
function calculateRiskScore($analysisResult) {
    $score = 0;
    $totalMatches = $analysisResult['total_matches'];
    $detectedTypes = $analysisResult['detected_types'];
    
    $riskWeights = [
        'kra_pin' => 15,
        'id_number' => 12,
        'bank_account' => 10,
        'phone' => 5,
        'email' => 3
    ];
    
    foreach ($detectedTypes as $type) {
        if (isset($riskWeights[$type])) {
            $score += $riskWeights[$type];
        }
    }
    
    // Volume factor
    if ($totalMatches > 0) {
        $volumeFactor = min(30, $totalMatches * 2);
        $score += $volumeFactor;
    }
    
    // Type diversity bonus
    $typeCount = count($detectedTypes);
    if ($typeCount >= 3) {
        $score += 15;
    } elseif ($typeCount >= 2) {
        $score += 8;
    }
    
    return min(100, $score);
}

/**
 * Get Risk Level
 */
function getRiskLevel($score) {
    if ($score >= 70) return 'Critical';
    if ($score >= 50) return 'High';
    if ($score >= 25) return 'Medium';
    return 'Low';
}

/**
 * Recommendation Message
 */
function getRecommendationMessage($riskScore, $analysisResult) {
    if ($riskScore >= 70) {
        return "⚠️ CRITICAL RISK: Highly sensitive data (KRA PIN, ID numbers) detected. Anonymize immediately before sharing.";
    } elseif ($riskScore >= 50) {
        return "🔴 HIGH RISK: Multiple sensitive data types found. Use Maskit to anonymize.";
    } elseif ($riskScore >= 25) {
        return "🟡 MEDIUM RISK: Personal data detected. Consider anonymizing before sharing.";
    } elseif ($analysisResult['total_matches'] > 0) {
        return "🟢 LOW RISK: Minimal contact information detected. Generally safe.";
    } else {
        return "✅ NO PII DETECTED: File appears to contain no personal data.";
    }
}
?>