<?php
require_once __DIR__ . '/../connection.php';
require_once __DIR__ . '/../vendor/autoload.php';

use Firebase\JWT\JWT;

class AuthController {
    private $conn;
    private $admin_mobile = '9524666087'; // Admin mobile number from company table

    public function __construct($db) {
        $this->conn = $db;
        // Set timezone to avoid any time-related issues
        date_default_timezone_set('Asia/Kolkata');
        $this->conn->query("SET time_zone = '+05:30'");
    }

    // Generate OTP for collection agent or admin
    public function generateOTP($mobile_no) {
        try {
            // Validate mobile number
            if (empty($mobile_no) || !preg_match('/^[0-9]{10}$/', $mobile_no)) {
                return ['status' => 'error', 'message' => 'Invalid mobile number'];
            }
            
            // First, check if it's a collection agent
            try {
                $query = "SELECT id, name, status FROM xesstech_dayloan.collection_agent WHERE mobile_no = ?";
                $stmt = $this->conn->prepare($query);
                $stmt->bind_param("s", $mobile_no);
                $stmt->execute();
                $result = $stmt->get_result();
                
                if ($result->num_rows > 0) {
                    $agent = $result->fetch_assoc();
                    if (strtolower($agent['status']) !== 'active') {
                        return ['status' => 'error', 'message' => 'Your account is not active. Please contact administrator.'];
                    }
                    
                    // Generate and store OTP for collection agent
                    return $this->generateAndStoreOTP($mobile_no, $agent['id']);
                }
            } catch (Exception $e) {
                error_log("Error checking collection agent: " . $e->getMessage());
            }
            
            // If not a collection agent, check if it's an admin (in registration table)
            try {
                $query = "SELECT id, com_name, email, mob_num 
                         FROM xesstech_dayloan.registration 
                         WHERE mob_num = ? AND status = 'active' 
                         LIMIT 1";
                $stmt = $this->conn->prepare($query);
                $stmt->bind_param("s", $mobile_no);
                $stmt->execute();
                $result = $stmt->get_result();
                
                if ($result->num_rows > 0) {
                    $admin = $result->fetch_assoc();
                    
                    // Return admin login response without OTP
                    return [
                        'status' => 'success',
                        'message' => 'Admin login detected',
                        'token_expires' => date('Y-m-d H:i:s', strtotime('+8 hours')),
                        'Admin' => [
                            'id' => $admin['id'],
                            'mobile_no' => $admin['mob_num'],
                            'company_name' => $admin['com_name'],
                            'email' => $admin['email']
                        ]
                    ];
                }
            } catch (Exception $e) {
                error_log("Error checking admin registration: " . $e->getMessage());
            }
            
            // If we get here, the number is not registered as either agent or admin
            return ['status' => 'error', 'message' => 'Mobile number not registered'];
            
        } catch (Exception $e) {
            error_log("OTP Generation Error: " . $e->getMessage());
            return ['status' => 'error', 'message' => 'Failed to process your request. Please try again.'];
        }
    }
    
    // Helper function to generate and store OTP
    private function generateAndStoreOTP($mobile_no, $agent_id) {
        try {
            // Check if the OTP table exists
            $tableCheck = $this->conn->query("SHOW TABLES LIKE 'collection_agent_otp'");
            if ($tableCheck->num_rows === 0) {
                // Create the OTP table if it doesn't exist
                $createTableSQL = "
                    CREATE TABLE IF NOT EXISTS `collection_agent_otp` (
                        `id` int NOT NULL AUTO_INCREMENT,
                        `agent_id` int NOT NULL,
                        `mobile_no` varchar(15) NOT NULL,
                        `otp` varchar(10) NOT NULL,
                        `expires_at` datetime NOT NULL,
                        `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        `is_used` tinyint(1) NOT NULL DEFAULT '0',
                        PRIMARY KEY (`id`),
                        KEY `mobile_no` (`mobile_no`),
                        KEY `expires_at` (`expires_at`),
                        KEY `is_used` (`is_used`)
                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
                ";
                
                if (!$this->conn->query($createTableSQL)) {
                    throw new Exception("Failed to create OTP table: " . $this->conn->error);
                }
            }
            
            $otp = str_pad(rand(0, 999999), 6, '0', STR_PAD_LEFT);
            $expires_at = date('Y-m-d H:i:s', strtotime('+5 minutes'));

            // Start transaction
            $this->conn->begin_transaction();

            // Delete any existing OTPs
            $query = "DELETE FROM collection_agent_otp WHERE mobile_no = ?";
            $stmt = $this->conn->prepare($query);
            if (!$stmt) {
                throw new Exception("Prepare failed: " . $this->conn->error);
            }
            
            $stmt->bind_param("s", $mobile_no);
            if (!$stmt->execute()) {
                throw new Exception("Delete failed: " . $stmt->error);
            }

            // Insert new OTP
            $query = "INSERT INTO collection_agent_otp (agent_id, mobile_no, otp, expires_at) 
                     VALUES (?, ?, ?, ?)";
            $stmt = $this->conn->prepare($query);
            if (!$stmt) {
                throw new Exception("Prepare failed: " . $this->conn->error);
            }
            
            $stmt->bind_param("isss", $agent_id, $mobile_no, $otp, $expires_at);
            
            if (!$stmt->execute()) {
                throw new Exception("Insert failed: " . $stmt->error);
            }

            $this->conn->commit();

            // In production, send OTP via SMS gateway here
            error_log("OTP generated for mobile: $mobile_no - $otp");
            return [
                'status' => 'success',
                'message' => 'OTP generated successfully',
                'otp' => $otp, // Remove this in production
                'expires_in' => 300 // 5 minutes
            ];

        } catch (Exception $e) {
            if (isset($this->conn)) {
                $this->conn->rollback();
            }
            error_log("OTP Generation Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
            error_log("Stack trace: " . $e->getTraceAsString());
            return ['status' => 'error', 'message' => 'Failed to generate OTP. Please try again.'];
        }
    }

    // Verify OTP for collection agent login
    public function verifyOTP($mobile_no, $otp, $device_id, $device_token = null, $device_type = null) {
        try {
            // Input validation
            if (empty($mobile_no) || empty($otp) || empty($device_id)) {
                return ['status' => 'error', 'message' => 'Missing required fields'];
            }

            // Clean up expired OTPs first
            $cleanup = "DELETE FROM collection_agent_otp WHERE expires_at <= NOW()";
            $this->conn->query($cleanup);

            // Verify OTP with case-sensitive comparison and check agent status
            $query = "SELECT ca.*, cao.otp, cao.expires_at as otp_expiry
                     FROM collection_agent_otp cao
                     JOIN collection_agent ca ON cao.agent_id = ca.id
                     WHERE cao.mobile_no = ? 
                     AND cao.otp = ?
                     AND cao.expires_at > NOW()
                     AND cao.is_verified = 0
                     AND LOWER(ca.status) = 'active'
                     LIMIT 1";
            
            $stmt = $this->conn->prepare($query);
            $stmt->bind_param("ss", $mobile_no, $otp);
            $stmt->execute();
            $result = $stmt->get_result();
            
            if ($result->num_rows === 0) {
                // Log the failure reason
                $check = "SELECT * FROM collection_agent_otp 
                         WHERE mobile_no = ? AND otp = ?";
                $stmt = $this->conn->prepare($check);
                $stmt->bind_param("ss", $mobile_no, $otp);
                $stmt->execute();
                $otp_data = $stmt->get_result()->fetch_assoc();
                
                $reason = 'Invalid OTP';
                if ($otp_data) {
                    if ($otp_data['is_verified']) $reason = 'OTP already used';
                    elseif (strtotime($otp_data['expires_at']) <= time()) $reason = 'OTP expired';
                }
                
                error_log("OTP Verification Failed: $reason - Mobile: $mobile_no");
                return ['status' => 'error', 'message' => $reason];
            }

            $agent = $result->fetch_assoc();
            
            // Double-check agent status
            if (strtolower($agent['status']) !== 'active') {
                return [
                    'status' => 'error', 
                    'message' => 'Your account is not active. Please contact administrator.'
                ];
            }
            
            // Check if already logged in from another device
            if ($agent['is_logged_in'] && $agent['device_id'] !== $device_id) {
                return [
                    'status' => 'error', 
                    'message' => 'Already logged in from another device',
                    'device_id' => $agent['device_id']
                ];
            }

            // Generate auth token
            $auth_token = bin2hex(random_bytes(32));
            $token_expires = date('Y-m-d H:i:s', strtotime('+24 hours'));

            // Start transaction
            $this->conn->begin_transaction();

            try {
                // Update agent session
                $query = "UPDATE collection_agent 
                         SET device_id = ?, 
                             device_token = ?,
                             device_type = ?,
                             auth_token = ?,
                             token_expires_at = ?,
                             is_logged_in = 1,
                             last_login = NOW(),
                             login_attempts = 0
                         WHERE id = ?";
                
                $stmt = $this->conn->prepare($query);
                $stmt->bind_param("sssssi", 
                    $device_id, 
                    $device_token, 
                    $device_type, 
                    $auth_token, 
                    $token_expires,
                    $agent['id']
                );

                if (!$stmt->execute() || $stmt->affected_rows === 0) {
                    throw new Exception("Failed to update agent session");
                }

                // Mark OTP as used
                $query = "UPDATE collection_agent_otp SET is_verified = 1 
                         WHERE mobile_no = ? AND otp = ?";
                $stmt = $this->conn->prepare($query);
                $stmt->bind_param("ss", $mobile_no, $otp);
                $stmt->execute();

                $this->conn->commit();

                // Remove sensitive data before returning
                unset($agent['otp']);
                unset($agent['auth_token']);
                unset($agent['otp_expiry']);
                
                return [
                    'status' => 'success',
                    'message' => 'Login successful',
                    'auth_token' => $auth_token,
                    'token_expires' => $token_expires,
                    'agent' => $agent
                ];

            } catch (Exception $e) {
                $this->conn->rollback();
                throw $e;
            }

        } catch (Exception $e) {
            error_log("OTP Verification Error: " . $e->getMessage());
            return ['status' => 'error', 'message' => 'An error occurred during verification'];
        }
    }

    // Logout
    public function logout($auth_token) {
        try {
            if (empty($auth_token)) {
                return ['status' => 'error', 'message' => 'Invalid token'];
            }

            $query = "UPDATE collection_agent 
                     SET auth_token = NULL,
                         token_expires_at = NULL,
                         is_logged_in = 0,
                         device_token = NULL
                     WHERE auth_token = ?";
            
            $stmt = $this->conn->prepare($query);
            $stmt->bind_param("s", $auth_token);
            
            if ($stmt->execute() && $stmt->affected_rows > 0) {
                return ['status' => 'success', 'message' => 'Logged out successfully'];
            }
            
            return ['status' => 'error', 'message' => 'Invalid or expired session'];

        } catch (Exception $e) {
            error_log("Logout Error: " . $e->getMessage());
            return ['status' => 'error', 'message' => 'Failed to logout'];
        }
    }

    // Admin login with username, password and company validation
    public function adminLogin($username, $password, $company_id) {
        try {
            // Input validation
            if (empty($username) || empty($password) || empty($company_id)) {
                return ['status' => 'error', 'message' => 'All fields are required'];
            }

            // Get admin details from staff table
            $query = "SELECT s.*, c.com_name, c.email as company_email 
                     FROM staff s 
                     JOIN company c ON s.com_id = c.com_id 
                     WHERE s.user_name = ? AND s.com_id = ? AND s.user_type = 'admin' 
                     LIMIT 1";
            
            $stmt = $this->conn->prepare($query);
            if (!$stmt) {
                throw new Exception("Database error: " . $this->conn->error);
            }
            
            $stmt->bind_param("si", $username, $company_id);
            
            if (!$stmt->execute()) {
                throw new Exception("Failed to execute query");
            }
            
            $result = $stmt->get_result();
            
            if ($result->num_rows === 0) {
                return ['status' => 'error', 'message' => 'Invalid credentials or admin not found'];
            }
            
            $admin = $result->fetch_assoc();
            
            // Verify password (assuming plain text for now, should be hashed in production)
            if ($admin['password'] !== $password) {
                return ['status' => 'error', 'message' => 'Invalid password'];
            }
            
            // Generate auth token (simple implementation, consider using JWT in production)
            $auth_token = bin2hex(random_bytes(32));
            $expires_at = date('Y-m-d H:i:s', strtotime('+8 hours'));
            
            // Store the token in database (you'll need to add this to your staff table)
            $updateToken = "UPDATE staff SET auth_token = ?, token_expires_at = ? WHERE uid = ?";
            $stmt = $this->conn->prepare($updateToken);
            $stmt->bind_param("ssi", $auth_token, $expires_at, $admin['uid']);
            
            if (!$stmt->execute()) {
                throw new Exception("Failed to update auth token");
            }
            
            // Return success response with admin details
            return [
                'status' => 'success',
                'message' => 'Login successful',
                'auth_token' => $auth_token,
                'token_expires' => $expires_at,
                'admin' => [
                    'id' => $admin['uid'],
                    'name' => $admin['name'],
                    'username' => $admin['user_name'],
                    'company_id' => $admin['com_id'],
                    'company_name' => $admin['com_name'],
                    'email' => $admin['company_email'],
                    'permissions' => json_decode($admin['permissions'], true) ?? []
                ]
            ];
            
        } catch (Exception $e) {
            error_log("Admin Login Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
            return ['status' => 'error', 'message' => 'An error occurred during login. Please try again.'];
        }
    }
    
    // Check if user is logged in
    public function isLoggedIn($auth_token) {
        try {
            if (empty($auth_token)) {
                return false;
            }

            $query = "SELECT id, name, mobile_no, is_logged_in, device_id 
                     FROM collection_agent 
                     WHERE auth_token = ? 
                     AND token_expires_at > NOW() 
                     AND is_logged_in = 1
                     LIMIT 1";
            
            $stmt = $this->conn->prepare($query);
            $stmt->bind_param("s", $auth_token);
            $stmt->execute();
            $result = $stmt->get_result();
            
            return $result->num_rows > 0 ? $result->fetch_assoc() : false;

        } catch (Exception $e) {
            error_log("Session Check Error: " . $e->getMessage());
            return false;
        }
    }
}
