<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Otp_model extends CI_Model {
    
    protected $table = 'otps';
    
    public function __construct() {
        parent::__construct();
    }
    
    /**
     * Generate a new OTP for a user
     * @param int $user_id User ID
     * @param string $purpose Purpose of OTP (transaction, login, etc.)
     * @param array $metadata Additional data to store with OTP
     * @return string The generated OTP code
     */
    public function generate($user_id, $purpose = 'transaction', $metadata = []) {
        // Invalidate any existing OTPs for this user and purpose
        $this->invalidate_existing($user_id, $purpose);
        
        // Generate 6-digit OTP
        $otp_code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
        
        // Set expiry (5 minutes from now)
        $this->config->load('email');
        $expiry_minutes = $this->config->item('otp_expiry_minutes') ?: 5;
        $expires_at = date('Y-m-d H:i:s', strtotime("+{$expiry_minutes} minutes"));
        
        // Store OTP
        $data = [
            'user_id' => $user_id,
            'otp_code' => password_hash($otp_code, PASSWORD_DEFAULT), // Hash the OTP
            'purpose' => $purpose,
            'metadata' => json_encode($metadata),
            'expires_at' => $expires_at,
            'attempts' => 0,
            'is_used' => 0,
            'created_at' => date('Y-m-d H:i:s')
        ];
        
        $this->db->insert($this->table, $data);
        
        return $otp_code;
    }
    
    /**
     * Verify an OTP
     * @param int $user_id User ID
     * @param string $otp_code The OTP code to verify
     * @param string $purpose Purpose of OTP
     * @return array Result with success status and message
     */
    public function verify($user_id, $otp_code, $purpose = 'transaction') {
        // Get the latest valid OTP for this user (purpose matching is optional for flexibility)
        $this->db->where('user_id', $user_id);
        $this->db->where('is_used', 0);
        $this->db->where('expires_at >', date('Y-m-d H:i:s'));
        $this->db->where('attempts <', 5); // Max 5 attempts
        $this->db->order_by('created_at', 'DESC');
        $this->db->limit(1);
        $otp = $this->db->get($this->table)->row();
        
        if (!$otp) {
            return [
                'success' => false,
                'message' => 'OTP has expired or is invalid. Please request a new one.'
            ];
        }
        
        // Increment attempts
        $this->db->where('id', $otp->id);
        $this->db->update($this->table, ['attempts' => $otp->attempts + 1]);
        
        // Verify the OTP
        if (!password_verify($otp_code, $otp->otp_code)) {
            $remaining_attempts = 4 - $otp->attempts;
            if ($remaining_attempts <= 0) {
                return [
                    'success' => false,
                    'message' => 'Too many incorrect attempts. Please request a new OTP.'
                ];
            }
            return [
                'success' => false,
                'message' => "Invalid OTP. {$remaining_attempts} attempts remaining."
            ];
        }
        
        // Mark OTP as used
        $this->db->where('id', $otp->id);
        $this->db->update($this->table, ['is_used' => 1]);
        
        return [
            'success' => true,
            'message' => 'OTP verified successfully',
            'metadata' => json_decode($otp->metadata, true)
        ];
    }
    
    /**
     * Invalidate existing OTPs for a user
     */
    public function invalidate_existing($user_id, $purpose = null) {
        $this->db->where('user_id', $user_id);
        $this->db->where('is_used', 0);
        $this->db->update($this->table, ['is_used' => 1]);
    }
    
    /**
     * Check if user can request a new OTP (rate limiting)
     * @param int $user_id User ID
     * @param string $purpose Purpose (unused but kept for API compatibility)
     * @return bool
     */
    public function can_request_new($user_id, $purpose = 'transaction') {
        // Check if an OTP was sent in the last 60 seconds
        $this->db->where('user_id', $user_id);
        $this->db->where('created_at >', date('Y-m-d H:i:s', strtotime('-60 seconds')));
        $recent = $this->db->get($this->table)->row();
        
        return !$recent;
    }
    
    /**
     * Get time until user can request new OTP
     * @param int $user_id User ID
     * @param string $purpose Purpose (unused but kept for API compatibility)
     * @return int Seconds remaining
     */
    public function get_cooldown_remaining($user_id, $purpose = 'transaction') {
        $this->db->select('created_at');
        $this->db->where('user_id', $user_id);
        $this->db->order_by('created_at', 'DESC');
        $this->db->limit(1);
        $otp = $this->db->get($this->table)->row();
        
        if (!$otp) {
            return 0;
        }
        
        $created = strtotime($otp->created_at);
        $cooldown_end = $created + 60;
        $remaining = $cooldown_end - time();
        
        return max(0, $remaining);
    }
    
    /**
     * Clean up expired OTPs (can be called via cron)
     */
    public function cleanup_expired() {
        $this->db->where('expires_at <', date('Y-m-d H:i:s'));
        $this->db->delete($this->table);
        return $this->db->affected_rows();
    }
}
