<?php
/**
 * Member Service
 * Handles all member-related operations
 * Kenyan Pension & Life Insurance Management System
 * 
 * @package Classes
 * @author Senior Fintech Engineer
 */

require_once __DIR__ . '/EncryptionService.php';

class MemberService {
    private $conn;
    private $encryption;
    
    /**
     * Constructor
     * 
     * @param mysqli $conn Database connection
     */
    public function __construct($conn) {
        $this->conn = $conn;
        $this->encryption = new EncryptionService();
    }
    
    /**
     * Create a new member
     * 
     * @param array $memberData Member data
     * @return array Result with member_id or error
     */
    public function createMember($memberData) {
        try {
            // Validate required fields
            $required = ['scheme_id', 'member_number', 'first_name', 'last_name', 'date_of_birth'];
            foreach ($required as $field) {
                if (empty($memberData[$field])) {
                    return ['success' => false, 'message' => "Field {$field} is required"];
                }
            }
            
            // Encrypt PII data
            $piiFields = ['national_id', 'phone_number', 'email'];
            $memberData = $this->encryption->encryptFields($memberData, $piiFields);
            
            // Start transaction
            $this->conn->begin_transaction();
            
            // Insert member
            $sql = "INSERT INTO members (
                scheme_id, employer_id, member_number, national_id, first_name, middle_name, 
                last_name, date_of_birth, gender, email, phone_number, employment_status,
                date_of_employment, is_active
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
            
            $stmt = $this->conn->prepare($sql);
            $stmt->bind_param(
                "iisssssssssssi",
                $memberData['scheme_id'],
                $memberData['employer_id'] ?? null,
                $memberData['member_number'],
                $memberData['national_id'] ?? null,
                $memberData['first_name'],
                $memberData['middle_name'] ?? null,
                $memberData['last_name'],
                $memberData['date_of_birth'],
                $memberData['gender'] ?? null,
                $memberData['email'] ?? null,
                $memberData['phone_number'] ?? null,
                $memberData['employment_status'] ?? 'ACTIVE',
                $memberData['date_of_employment'] ?? null,
                $memberData['is_active'] ?? 1
            );
            
            if (!$stmt->execute()) {
                throw new Exception("Failed to create member: " . $stmt->error);
            }
            
            $member_id = $this->conn->insert_id;
            
            // Create member account
            $accountSql = "INSERT INTO member_accounts (member_id) VALUES (?)";
            $accountStmt = $this->conn->prepare($accountSql);
            $accountStmt->bind_param("i", $member_id);
            
            if (!$accountStmt->execute()) {
                throw new Exception("Failed to create member account: " . $accountStmt->error);
            }
            
            // Commit transaction
            $this->conn->commit();
            
            // Log activity
            $this->logActivity($member_id, 'MEMBER_CREATED', 'MEMBER', $member_id, null, $memberData);
            
            return [
                'success' => true,
                'message' => 'Member created successfully',
                'member_id' => $member_id
            ];
            
        } catch (Exception $e) {
            $this->conn->rollback();
            error_log("MemberService::createMember Error: " . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Failed to create member: ' . $e->getMessage()
            ];
        }
    }
    
    /**
     * Get member by ID
     * 
     * @param int $member_id Member ID
     * @return array|null Member data or null
     */
    public function getMember($member_id) {
        $sql = "SELECT m.*, ps.scheme_name, ps.scheme_type, 
                       e.employer_name, ma.accrued_benefits, ma.available_balance
                FROM members m
                LEFT JOIN pension_schemes ps ON m.scheme_id = ps.scheme_id
                LEFT JOIN employers e ON m.employer_id = e.employer_id
                LEFT JOIN member_accounts ma ON m.member_id = ma.member_id
                WHERE m.member_id = ? AND m.is_active = 1";
        
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("i", $member_id);
        $stmt->execute();
        $result = $stmt->get_result();
        
        if ($member = $result->fetch_assoc()) {
            // Decrypt PII data
            $member = $this->encryption->decryptFields($member, ['national_id', 'phone_number', 'email']);
            return $member;
        }
        
        return null;
    }
    
    /**
     * Update member
     * 
     * @param int $member_id Member ID
     * @param array $memberData Updated member data
     * @return array Result
     */
    public function updateMember($member_id, $memberData) {
        try {
            // Get old data for audit
            $oldData = $this->getMember($member_id);
            if (!$oldData) {
                return ['success' => false, 'message' => 'Member not found'];
            }
            
            // Encrypt PII data
            $piiFields = ['national_id', 'phone_number', 'email'];
            $memberData = $this->encryption->encryptFields($memberData, $piiFields);
            
            // Build update query dynamically
            $updates = [];
            $types = '';
            $values = [];
            
            $allowedFields = [
                'first_name', 'middle_name', 'last_name', 'date_of_birth', 'gender',
                'email', 'phone_number', 'employment_status', 'date_of_employment',
                'date_of_termination', 'is_permanently_disabled', 'is_emigrated',
                'disability_certificate_date', 'emigration_date', 'is_active'
            ];
            
            foreach ($allowedFields as $field) {
                if (isset($memberData[$field])) {
                    $updates[] = "$field = ?";
                    $types .= $this->getBindType($memberData[$field]);
                    $values[] = $memberData[$field];
                }
            }
            
            if (empty($updates)) {
                return ['success' => false, 'message' => 'No valid fields to update'];
            }
            
            $values[] = $member_id;
            $types .= 'i';
            
            $sql = "UPDATE members SET " . implode(', ', $updates) . " WHERE member_id = ?";
            $stmt = $this->conn->prepare($sql);
            $stmt->bind_param($types, ...$values);
            
            if (!$stmt->execute()) {
                throw new Exception("Failed to update member: " . $stmt->error);
            }
            
            // Log activity
            $this->logActivity($member_id, 'MEMBER_UPDATED', 'MEMBER', $member_id, $oldData, $memberData);
            
            return [
                'success' => true,
                'message' => 'Member updated successfully'
            ];
            
        } catch (Exception $e) {
            error_log("MemberService::updateMember Error: " . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Failed to update member: ' . $e->getMessage()
            ];
        }
    }
    
    /**
     * Get member list with pagination
     * 
     * @param array $filters Search filters
     * @param int $page Page number
     * @param int $perPage Records per page
     * @return array Members list and pagination info
     */
    public function getMembers($filters = [], $page = 1, $perPage = 20) {
        $offset = ($page - 1) * $perPage;
        
        // Build WHERE clause
        $where = ["m.is_active = 1"];
        $params = [];
        $types = '';
        
        if (!empty($filters['scheme_id'])) {
            $where[] = "m.scheme_id = ?";
            $params[] = $filters['scheme_id'];
            $types .= 'i';
        }
        
        if (!empty($filters['employer_id'])) {
            $where[] = "m.employer_id = ?";
            $params[] = $filters['employer_id'];
            $types .= 'i';
        }
        
        if (!empty($filters['employment_status'])) {
            $where[] = "m.employment_status = ?";
            $params[] = $filters['employment_status'];
            $types .= 's';
        }
        
        if (!empty($filters['search'])) {
            $where[] = "(m.member_number LIKE ? OR m.first_name LIKE ? OR m.last_name LIKE ?)";
            $searchTerm = '%' . $filters['search'] . '%';
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $types .= 'sss';
        }
        
        $whereClause = implode(' AND ', $where);
        
        // Get total count
        $countSql = "SELECT COUNT(*) as total FROM members m WHERE $whereClause";
        $countStmt = $this->conn->prepare($countSql);
        if (!empty($params)) {
            $countStmt->bind_param($types, ...$params);
        }
        $countStmt->execute();
        $total = $countStmt->get_result()->fetch_assoc()['total'];
        
        // Get members
        $sql = "SELECT m.member_id, m.member_number, m.first_name, m.last_name, 
                       m.date_of_birth, m.employment_status, m.date_of_employment,
                       ps.scheme_name, ps.scheme_type, e.employer_name,
                       ma.accrued_benefits, ma.available_balance
                FROM members m
                LEFT JOIN pension_schemes ps ON m.scheme_id = ps.scheme_id
                LEFT JOIN employers e ON m.employer_id = e.employer_id
                LEFT JOIN member_accounts ma ON m.member_id = ma.member_id
                WHERE $whereClause
                ORDER BY m.created_at DESC
                LIMIT ? OFFSET ?";
        
        $params[] = $perPage;
        $params[] = $offset;
        $types .= 'ii';
        
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param($types, ...$params);
        $stmt->execute();
        $result = $stmt->get_result();
        
        $members = [];
        while ($row = $result->fetch_assoc()) {
            // Decrypt PII if needed (for display, we might not show all PII)
            $members[] = $row;
        }
        
        return [
            'members' => $members,
            'pagination' => [
                'page' => $page,
                'per_page' => $perPage,
                'total' => $total,
                'total_pages' => ceil($total / $perPage)
            ]
        ];
    }
    
    /**
     * Add beneficiary to member
     * 
     * @param int $member_id Member ID
     * @param array $beneficiaryData Beneficiary data
     * @return array Result
     */
    public function addBeneficiary($member_id, $beneficiaryData) {
        try {
            // Validate member exists
            if (!$this->getMember($member_id)) {
                return ['success' => false, 'message' => 'Member not found'];
            }
            
            // Encrypt PII
            $beneficiaryData = $this->encryption->encryptFields(
                $beneficiaryData, 
                ['national_id', 'phone_number', 'email']
            );
            
            $sql = "INSERT INTO beneficiaries (
                member_id, first_name, last_name, relationship, date_of_birth,
                national_id, phone_number, email, address, allocation_percentage
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
            
            $stmt = $this->conn->prepare($sql);
            $stmt->bind_param(
                "issssssssd",
                $member_id,
                $beneficiaryData['first_name'],
                $beneficiaryData['last_name'],
                $beneficiaryData['relationship'],
                $beneficiaryData['date_of_birth'] ?? null,
                $beneficiaryData['national_id'] ?? null,
                $beneficiaryData['phone_number'] ?? null,
                $beneficiaryData['email'] ?? null,
                $beneficiaryData['address'] ?? null,
                $beneficiaryData['allocation_percentage'] ?? 100.00
            );
            
            if (!$stmt->execute()) {
                throw new Exception("Failed to add beneficiary: " . $stmt->error);
            }
            
            $beneficiary_id = $this->conn->insert_id;
            
            // Log activity
            $this->logActivity($member_id, 'BENEFICIARY_ADDED', 'MEMBER', $member_id, null, $beneficiaryData);
            
            return [
                'success' => true,
                'message' => 'Beneficiary added successfully',
                'beneficiary_id' => $beneficiary_id
            ];
            
        } catch (Exception $e) {
            error_log("MemberService::addBeneficiary Error: " . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Failed to add beneficiary: ' . $e->getMessage()
            ];
        }
    }
    
    /**
     * Get member beneficiaries
     * 
     * @param int $member_id Member ID
     * @return array Beneficiaries list
     */
    public function getBeneficiaries($member_id) {
        $sql = "SELECT * FROM beneficiaries 
                WHERE member_id = ? AND is_active = 1
                ORDER BY created_at DESC";
        
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("i", $member_id);
        $stmt->execute();
        $result = $stmt->get_result();
        
        $beneficiaries = [];
        while ($row = $result->fetch_assoc()) {
            // Decrypt PII
            $row = $this->encryption->decryptFields($row, ['national_id', 'phone_number', 'email', 'address']);
            $beneficiaries[] = $row;
        }
        
        return $beneficiaries;
    }
    
    /**
     * Get bind type for prepared statement
     */
    private function getBindType($value) {
        if (is_int($value)) return 'i';
        if (is_float($value)) return 'd';
        return 's';
    }
    
    /**
     * Log activity
     */
    private function logActivity($user_id, $event_type, $event_category, $entity_id, $old_value, $new_value) {
        global $conn;
        
        $sql = "INSERT INTO audit_logs (
            event_type, event_category, member_id, event_description, 
            old_value, new_value, performed_by, ip_address, created_at
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)";
        
        $stmt = $conn->prepare($sql);
        $event_description = "Member operation: $event_type";
        $performed_by = $_SESSION['username'] ?? 'SYSTEM';
        $ip_address = $_SERVER['REMOTE_ADDR'] ?? null;
        
        $old_json = $old_value ? json_encode($old_value) : null;
        $new_json = $new_value ? json_encode($new_value) : null;
        
        $stmt->bind_param("ssisssss", 
            $event_type, $event_category, $entity_id, $event_description,
            $old_json, $new_json, $performed_by, $ip_address
        );
        
        $stmt->execute();
    }
}
