<?php

/**

 * GESMIS (Ghana Education Service Management Information System) Adapter

 * Handles import from GESMIS export formats

 */



define('MIGRATION_ACCESS', true);

require_once '../config.php';

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

require_once '../cleansing/phone_formatter.php';

require_once '../cleansing/name_formatter.php';



class GESMISAdapter {

    private $conn;

    private $mappings;

    

    public function __construct($conn) {

        $this->conn = $conn;

        $this->mappings = [

            'students' => $this->getStudentMapping(),

            'staff' => $this->getStaffMapping(),

            'classes' => $this->getClassMapping(),

            'results' => $this->getResultMapping()

        ];

    }

    

    /**

     * Parse GESMIS export file

     */

    public function parseFile($filePath, $type) {

        $content = file_get_contents($filePath);

        

        // GESMIS typically exports in specific formats

        if ($this->isJSON($content)) {

            return $this->parseJSON($content, $type);

        } elseif ($this->isXML($content)) {

            return $this->parseXML($content, $type);

        } else {

            return $this->parseCSV($filePath, $type);

        }

    }

    

    /**

     * Transform GESMIS data to system format

     */

    public function transform($data, $type) {

        $mapping = $this->mappings[$type];

        $transformed = [];

        

        foreach ($data as $record) {

            $mapped = [];

            foreach ($mapping as $systemField => $gesmisField) {

                if (isset($record[$gesmisField])) {

                    $mapped[$systemField] = $this->transformField($record[$gesmisField], $systemField);

                }

            }

            $transformed[] = $mapped;

        }

        

        return $transformed;

    }

    

    /**

     * Import GESMIS data directly

     */

    public function import($filePath, $type, $options = []) {

        $data = $this->parseFile($filePath, $type);

        $transformed = $this->transform($data, $type);

        

        $results = [

            'total' => count($transformed),

            'imported' => 0,

            'failed' => 0,

            'errors' => []

        ];

        

        $this->conn->begin_transaction();

        

        try {

            foreach ($transformed as $index => $record) {

                $success = $this->insertRecord($record, $type, $options);

                if ($success) {

                    $results['imported']++;

                } else {

                    $results['failed']++;

                    $results['errors'][] = [

                        'row' => $index + 1,

                        'record' => $record,

                        'error' => 'Insert failed'

                    ];

                }

            }

            

            $this->conn->commit();

            

        } catch (Exception $e) {

            $this->conn->rollback();

            $results['error'] = $e->getMessage();

        }

        

        return $results;

    }

    

    private function getStudentMapping() {

        return [

            'student_id' => 'GESMIS_ID',

            'first_name' => 'FIRST_NAME',

            'last_name' => 'SURNAME',

            'other_names' => 'OTHER_NAMES',

            'date_of_birth' => 'DOB',

            'gender' => 'GENDER',

            'class' => 'CLASS_CODE',

            'class_name' => 'CLASS_NAME',

            'house_no' => 'HOUSE_NO',

            'father_name' => 'FATHER_NAME',

            'father_occupation' => 'FATHER_OCC',

            'father_phone' => 'FATHER_TEL',

            'mother_name' => 'MOTHER_NAME',

            'mother_occupation' => 'MOTHER_OCC',

            'mother_phone' => 'MOTHER_TEL',

            'guardian_name' => 'GUARDIAN_NAME',

            'guardian_phone' => 'GUARDIAN_TEL',

            'religion' => 'RELIGION',

            'nationality' => 'NATIONALITY',

            'hometown' => 'HOMETOWN',

            'enrollment_date' => 'ENROLL_DATE',

            'previous_school' => 'PREV_SCHOOL'

        ];

    }

    

    private function getStaffMapping() {

        return [

            'staff_id' => 'STAFF_ID',

            'full_name' => 'FULL_NAME',

            'gender' => 'GENDER',

            'date_of_birth' => 'DOB',

            'qualification' => 'QUALIFICATION',

            'specialization' => 'SPECIALIZATION',

            'rank' => 'RANK',

            'date_of_first_appointment' => 'APPOINTMENT_DATE',

            'date_of_current_rank' => 'RANK_DATE',

            'class_taught' => 'CLASS_TAUGHT',

            'subjects' => 'SUBJECTS',

            'phone' => 'PHONE',

            'email' => 'EMAIL',

            'bank_name' => 'BANK_NAME',

            'bank_account' => 'BANK_ACCOUNT',

            'ssnit_number' => 'SSNIT',

            'tin_number' => 'TIN'

        ];

    }

    

    private function getClassMapping() {

        return [

            'class_code' => 'CLASS_CODE',

            'class_name' => 'CLASS_NAME',

            'section' => 'SECTION',

            'class_teacher' => 'CLASS_TEACHER',

            'academic_year' => 'ACAD_YEAR',

            'capacity' => 'CAPACITY',

            'streams' => 'STREAMS'

        ];

    }

    

    private function getResultMapping() {

        return [

            'student_id' => 'STUDENT_ID',

            'subject_code' => 'SUBJECT_CODE',

            'subject_name' => 'SUBJECT_NAME',

            'class_score' => 'CLASS_SCORE',

            'exam_score' => 'EXAM_SCORE',

            'total_score' => 'TOTAL_SCORE',

            'grade' => 'GRADE',

            'term' => 'TERM',

            'academic_year' => 'ACAD_YEAR',

            'teacher_remark' => 'REMARK'

        ];

    }

    

    private function transformField($value, $field) {

        if (empty($value)) return null;

        

        switch ($field) {

            case 'phone':

            case 'father_phone':

            case 'mother_phone':

            case 'guardian_phone':

                return formatGhanaPhone($value);

                

            case 'first_name':

            case 'last_name':

            case 'other_names':

            case 'full_name':

            case 'father_name':

            case 'mother_name':

            case 'guardian_name':

                return formatGhanaianName($value);

                

            case 'date_of_birth':

            case 'enrollment_date':

            case 'appointment_date':

            case 'rank_date':

                return $this->formatDate($value);

                

            case 'gender':

                return $this->formatGender($value);

                

            default:

                return trim($value);

        }

    }

    

    private function formatDate($value) {

        // Handle GESMIS date formats (DD/MM/YYYY or DD-MM-YYYY)

        $value = trim($value);

        

        if (preg_match('/^(\d{2})[\/\-](\d{2})[\/\-](\d{4})$/', $value, $matches)) {

            return "{$matches[3]}-{$matches[2]}-{$matches[1]}";

        }

        

        // Try standard formats

        $timestamp = strtotime($value);

        if ($timestamp) {

            return date('Y-m-d', $timestamp);

        }

        

        return $value;

    }

    

    private function formatGender($value) {

        $value = strtoupper(trim($value));

        

        if ($value == 'M' || $value == 'MALE') return 'Male';

        if ($value == 'F' || $value == 'FEMALE') return 'Female';

        

        return $value;

    }

    

    private function isJSON($string) {

        json_decode($string);

        return (json_last_error() == JSON_ERROR_NONE);

    }

    

    private function isXML($string) {

        $previous = libxml_use_internal_errors(true);

        $doc = simplexml_load_string($string);

        libxml_use_internal_errors($previous);

        return $doc !== false;

    }

    

    private function parseJSON($content, $type) {

        $data = json_decode($content, true);

        

        // GESMIS JSON structure varies

        if (isset($data[$type])) {

            return $data[$type];

        } elseif (isset($data['data'][$type])) {

            return $data['data'][$type];

        } elseif (is_array($data)) {

            return $data;

        }

        

        return [];

    }

    

    private function parseXML($content, $type) {

        $xml = simplexml_load_string($content);

        $json = json_encode($xml);

        $array = json_decode($json, true);

        

        if (isset($array[$type])) {

            return $array[$type];

        } elseif (isset($array['record'])) {

            return $array['record'];

        }

        

        return [];

    }

    

    private function parseCSV($filePath, $type) {

        $handle = fopen($filePath, 'r');

        $headers = fgetcsv($handle);

        $data = [];

        

        while ($row = fgetcsv($handle)) {

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

        }

        

        fclose($handle);

        return $data;

    }

    

    private function insertRecord($record, $type, $options) {

        switch ($type) {

            case 'students':

                return $this->insertStudent($record, $options);

            case 'staff':

                return $this->insertStaff($record, $options);

            case 'classes':

                return $this->insertClass($record, $options);

            case 'results':

                return $this->insertResult($record, $options);

            default:

                return false;

        }

    }

    

    private function insertStudent($record, $options) {

        // Check if student already exists

        $check = $this->conn->query("SELECT id FROM students WHERE student_id = '{$record['student_id']}'");

        if ($check->num_rows > 0 && empty($options['overwrite'])) {

            return false;

        }

        

        // Prepare data

        $data = [

            'student_id' => $record['student_id'] ?? $this->generateStudentId(),

            'first_name' => $record['first_name'] ?? '',

            'last_name' => $record['last_name'] ?? '',

            'sex' => $record['gender'] ?? null,

            'date_of_birth' => $record['date_of_birth'] ?? null,

            'class' => $record['class_name'] ?? $record['class'] ?? 'Not Assigned',

            'house_no' => $record['house_no'] ?? null,

            'father_name' => $record['father_name'] ?? null,

            'father_phone' => $record['father_phone'] ?? null,

            'mother_name' => $record['mother_name'] ?? null,

            'mother_phone' => $record['mother_phone'] ?? null,

            'religion' => $record['religion'] ?? null,

            'nationality' => $record['nationality'] ?? 'Ghanaian',

            'status' => 'active'

        ];

        

        // Insert or update

        if ($check->num_rows > 0) {

            return $this->updateStudent($check->fetch_assoc()['id'], $data);

        } else {

            return $this->createStudent($data);

        }

    }

    

    private function createStudent($data) {

        $query = "INSERT INTO students (

            student_id, first_name, last_name, sex, date_of_birth,

            class, house_no, father_name, father_phone, mother_name,

            mother_phone, religion, nationality, status

        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

        

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

        $stmt->bind_param(

            "ssssssssssssss",

            $data['student_id'],

            $data['first_name'],

            $data['last_name'],

            $data['sex'],

            $data['date_of_birth'],

            $data['class'],

            $data['house_no'],

            $data['father_name'],

            $data['father_phone'],

            $data['mother_name'],

            $data['mother_phone'],

            $data['religion'],

            $data['nationality'],

            $data['status']

        );

        

        return $stmt->execute();

    }

    

    private function updateStudent($id, $data) {

        $query = "UPDATE students SET

            first_name = ?, last_name = ?, sex = ?, date_of_birth = ?,

            class = ?, house_no = ?, father_name = ?, father_phone = ?,

            mother_name = ?, mother_phone = ?, religion = ?, nationality = ?

            WHERE id = ?";

        

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

        $stmt->bind_param(

            "ssssssssssssi",

            $data['first_name'],

            $data['last_name'],

            $data['sex'],

            $data['date_of_birth'],

            $data['class'],

            $data['house_no'],

            $data['father_name'],

            $data['father_phone'],

            $data['mother_name'],

            $data['mother_phone'],

            $data['religion'],

            $data['nationality'],

            $id

        );

        

        return $stmt->execute();

    }

    

    private function insertStaff($record, $options) {

        // Similar implementation for staff

        return true;

    }

    

    private function insertClass($record, $options) {

        // Similar implementation for classes

        return true;

    }

    

    private function insertResult($record, $options) {

        // Similar implementation for results

        return true;

    }

    

    private function generateStudentId() {

        $result = $this->conn->query("SELECT MAX(CAST(SUBSTRING(student_id, 4) AS UNSIGNED)) as max FROM students WHERE student_id LIKE 'STU%'");

        $row = $result->fetch_assoc();

        $next = ($row['max'] ?? 0) + 1;

        return 'STU' . str_pad($next, 3, '0', STR_PAD_LEFT);

    }

}

?>