<?php

/**

 * Background Import Processor

 * Handles large imports as background jobs

 */



define('MIGRATION_ACCESS', true);

require_once '../config.php';

require_once '../validation/validator.php';



class ImportProcessor {

    private $conn;

    private $jobId;

    private $batchSize = 100;

    

    public function __construct($jobId) {

        $this->conn = getDBConnection();

        $this->jobId = $jobId;

    }

    

    public function process() {

        // Get job details

        $job = $this->getJob();

        if (!$job) {

            return false;

        }

        

        // Update status to processing

        $this->updateJobStatus('processing');

        

        try {

            $file = fopen($job['file_path'], 'r');

            $headers = fgetcsv($file);

            

            $processed = 0;

            $successful = 0;

            $failed = 0;

            $batch = [];

            

            while (($row = fgetcsv($file)) !== FALSE) {

                $data = array_combine($headers, $row);

                $batch[] = $data;

                

                if (count($batch) >= $this->batchSize) {

                    $result = $this->importBatch($batch, $job['type']);

                    $successful += $result['success'];

                    $failed += $result['failed'];

                    $processed += count($batch);

                    

                    // Update progress

                    $this->updateProgress($processed, $successful, $failed);

                    

                    $batch = [];

                }

            }

            

            // Process remaining batch

            if (!empty($batch)) {

                $result = $this->importBatch($batch, $job['type']);

                $successful += $result['success'];

                $failed += $result['failed'];

                $processed += count($batch);

                $this->updateProgress($processed, $successful, $failed);

            }

            

            fclose($file);

            

            // Mark job as completed

            $this->completeJob($successful, $failed);

            

            // Log success

            logMigration("Job {$this->jobId} completed: $successful successful, $failed failed", 'SUCCESS');

            

        } catch (Exception $e) {

            $this->failJob($e->getMessage());

            logMigration("Job {$this->jobId} failed: " . $e->getMessage(), 'ERROR');

        }

    }

    

    private function importBatch($batch, $type) {

        $success = 0;

        $failed = 0;

        

        $this->conn->begin_transaction();

        

        try {

            foreach ($batch as $data) {

                // Validate first

                $validator = new DataValidator($this->conn);

                $validation = $validator->validate($data, $type);

                

                if ($validation['valid']) {

                    $this->insertRecord($data, $type);

                    $success++;

                } else {

                    $failed++;

                    // Log failed record

                    $this->logFailedRecord($data, $validation['errors']);

                }

            }

            

            $this->conn->commit();

            

        } catch (Exception $e) {

            $this->conn->rollback();

            throw $e;

        }

        

        return ['success' => $success, 'failed' => $failed];

    }

    

    private function insertRecord($data, $type) {

        // Implementation depends on type

        switch ($type) {

            case 'students':

                $this->insertStudent($data);

                break;

            case 'staff':

                $this->insertStaff($data);

                break;

            case 'payments':

                $this->insertPayment($data);

                break;

        }

    }

    

    private function insertStudent($data) {

        $query = "INSERT INTO students (

            student_id, first_name, last_name, class, section,

            parent_name, phone, email, address, status

        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'active')";

        

        $stmt = $this->conn->prepare($query);

        $stmt->bind_param(

            "sssssssss",

            $data['student_id'],

            $data['first_name'],

            $data['last_name'],

            $data['class'],

            $data['section'] ?? '',

            $data['parent_name'] ?? '',

            $data['phone'] ?? '',

            $data['email'] ?? '',

            $data['address'] ?? ''

        );

        $stmt->execute();

        $stmt->close();

    }

    

    // Other insert methods...

    

    private function getJob() {

        // In production, you'd store jobs in a database table

        // For now, we'll read from a simple file

        $jobFile = __DIR__ . "/../jobs/{$this->jobId}.json";

        if (file_exists($jobFile)) {

            return json_decode(file_get_contents($jobFile), true);

        }

        return null;

    }

    

    private function updateJobStatus($status) {

        $jobFile = __DIR__ . "/../jobs/{$this->jobId}.json";

        $job = $this->getJob();

        $job['status'] = $status;

        file_put_contents($jobFile, json_encode($job));

    }

    

    private function updateProgress($processed, $successful, $failed) {

        $jobFile = __DIR__ . "/../jobs/{$this->jobId}.json";

        $job = $this->getJob();

        $job['processed'] = $processed;

        $job['successful'] = $successful;

        $job['failed'] = $failed;

        $job['progress'] = round(($processed / $job['total']) * 100, 2);

        file_put_contents($jobFile, json_encode($job));

    }

    

    private function completeJob($successful, $failed) {

        $jobFile = __DIR__ . "/../jobs/{$this->jobId}.json";

        $job = $this->getJob();

        $job['status'] = 'completed';

        $job['successful'] = $successful;

        $job['failed'] = $failed;

        $job['completed_at'] = date('Y-m-d H:i:s');

        file_put_contents($jobFile, json_encode($job));

        

        // Clean up uploaded file

        if (file_exists($job['file_path'])) {

            unlink($job['file_path']);

        }

    }

    

    private function failJob($error) {

        $jobFile = __DIR__ . "/../jobs/{$this->jobId}.json";

        $job = $this->getJob();

        $job['status'] = 'failed';

        $job['error'] = $error;

        $job['failed_at'] = date('Y-m-d H:i:s');

        file_put_contents($jobFile, json_encode($job));

    }

    

    private function logFailedRecord($data, $errors) {

        $logFile = __DIR__ . "/../logs/failed_{$this->jobId}.log";

        $logEntry = date('Y-m-d H:i:s') . " | " . json_encode($data) . " | Errors: " . json_encode($errors) . "\n";

        file_put_contents($logFile, $logEntry, FILE_APPEND);

    }

}



// Run the processor if called directly

if (isset($argv[1])) {

    $processor = new ImportProcessor($argv[1]);

    $processor->process();

}

?>