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

class Card_model extends CI_Model {

    protected $table = 'cards';

    public function __construct() {
        parent::__construct();
    }

    /**
     * Get card by ID
     */
    public function get($id) {
        return $this->db->get_where($this->table, ['id' => $id])->row();
    }

    /**
     * Get cards for a user
     */
    public function get_by_user($user_id) {
        $this->db->select('cards.*, accounts.account_number, accounts.account_name');
        $this->db->from($this->table);
        $this->db->join('accounts', 'accounts.id = cards.account_id');
        $this->db->where('cards.user_id', $user_id);
        $this->db->order_by('cards.created_at', 'DESC');
        return $this->db->get()->result();
    }

    /**
     * Get all cards (admin)
     */
    public function get_all($filters = [], $limit = 50, $offset = 0) {
        $this->db->select('cards.*, users.first_name, users.last_name, users.email, accounts.account_number');
        $this->db->from($this->table);
        $this->db->join('users', 'users.id = cards.user_id');
        $this->db->join('accounts', 'accounts.id = cards.account_id');
        
        if (!empty($filters['status'])) {
            $this->db->where('cards.status', $filters['status']);
        }
        if (!empty($filters['card_type'])) {
            $this->db->where('cards.card_type', $filters['card_type']);
        }
        if (!empty($filters['user_id'])) {
            $this->db->where('cards.user_id', $filters['user_id']);
        }
        
        $this->db->order_by('cards.created_at', 'DESC');
        $this->db->limit($limit, $offset);
        
        return $this->db->get()->result();
    }

    /**
     * Create virtual card
     */
    public function create_virtual_card($user_id, $account_id, $currency = 'USD') {
        $this->load->model('User_model');
        $user = $this->User_model->get($user_id);
        
        if (!$user) {
            return ['success' => false, 'message' => 'User not found'];
        }
        
        // Generate card details
        $card_number = $this->generate_card_number();
        $expiry = $this->generate_expiry();
        $cvv = $this->generate_cvv();
        
        $data = [
            'user_id' => $user_id,
            'account_id' => $account_id,
            'card_type' => 'virtual',
            'card_brand' => 'mastercard',
            'card_number_masked' => '**** **** **** ' . substr($card_number, -4),
            'card_hash' => $this->encrypt_data($card_number),
            'expiry_month' => $expiry['month'],
            'expiry_year' => $expiry['year'],
            'cvv_hash' => $this->encrypt_data($cvv),
            'cardholder_name' => strtoupper($user->first_name . ' ' . $user->last_name),
            'currency' => $currency,
            'status' => 'inactive',
            'created_at' => date('Y-m-d H:i:s')
        ];
        
        $this->db->insert($this->table, $data);
        $card_id = $this->db->insert_id();
        
        if ($card_id) {
            return [
                'success' => true,
                'message' => 'Card created successfully',
                'card_id' => $card_id,
                'card_details' => [
                    'card_number' => $card_number,
                    'expiry' => $expiry['month'] . '/' . $expiry['year'],
                    'cvv' => $cvv
                ]
            ];
        }
        
        return ['success' => false, 'message' => 'Failed to create card'];
    }

    /**
     * Update card
     */
    public function update($id, $data) {
        $data['updated_at'] = date('Y-m-d H:i:s');
        return $this->db->update($this->table, $data, ['id' => $id]);
    }

    /**
     * Activate card
     */
    public function activate($id) {
        return $this->update($id, [
            'status' => 'active',
            'activated_at' => date('Y-m-d H:i:s')
        ]);
    }

    /**
     * Freeze card
     */
    public function freeze($id, $reason = null) {
        return $this->update($id, [
            'status' => 'frozen',
            'frozen_reason' => $reason,
            'frozen_at' => date('Y-m-d H:i:s')
        ]);
    }

    /**
     * Unfreeze card
     */
    public function unfreeze($id) {
        return $this->update($id, [
            'status' => 'active',
            'frozen_reason' => null,
            'frozen_at' => null
        ]);
    }

    /**
     * Block card
     */
    public function block($id) {
        return $this->update($id, ['status' => 'blocked']);
    }

    /**
     * Fund card
     */
    public function fund($card_id, $amount, $source_wallet_id) {
        $card = $this->get($card_id);
        
        if (!$card) {
            return ['success' => false, 'message' => 'Card not found'];
        }
        
        if ($card->status !== 'active') {
            return ['success' => false, 'message' => 'Card is not active'];
        }
        
        $this->load->model('Wallet_model');
        $this->load->model('Transaction_model');
        
        // Check source wallet balance
        if (!$this->Wallet_model->has_sufficient_balance($source_wallet_id, $amount)) {
            return ['success' => false, 'message' => 'Insufficient balance'];
        }
        
        // Calculate fee
        $fee = $this->Transaction_model->calculate_fee('card_funding', $amount);
        $total_debit = $amount + $fee;
        
        if (!$this->Wallet_model->has_sufficient_balance($source_wallet_id, $total_debit)) {
            return ['success' => false, 'message' => 'Insufficient balance for amount and fee'];
        }
        
        // Create transaction
        $transaction_id = $this->Transaction_model->create([
            'type' => 'card_funding',
            'source_wallet_id' => $source_wallet_id,
            'amount' => $amount,
            'fee' => $fee,
            'currency' => $card->currency,
            'narration' => 'Card funding - ' . $card->card_number_masked,
            'status' => 'processing',
            'metadata' => json_encode(['card_id' => $card_id])
        ]);
        
        // Debit wallet
        $this->Wallet_model->debit($source_wallet_id, $total_debit);
        
        // Credit card
        $new_balance = $card->balance + $amount;
        $this->update($card_id, ['balance' => $new_balance]);
        
        // Record card transaction
        $this->create_card_transaction([
            'card_id' => $card_id,
            'transaction_id' => $transaction_id,
            'type' => 'funding',
            'amount' => $amount,
            'currency' => $card->currency,
            'status' => 'approved'
        ]);
        
        // Update main transaction status
        $this->Transaction_model->update_status($transaction_id, 'completed');
        
        return [
            'success' => true,
            'message' => 'Card funded successfully',
            'new_balance' => $new_balance
        ];
    }

    /**
     * Withdraw from card
     */
    public function withdraw($card_id, $amount, $destination_wallet_id) {
        $card = $this->get($card_id);
        
        if (!$card) {
            return ['success' => false, 'message' => 'Card not found'];
        }
        
        if ($card->status !== 'active') {
            return ['success' => false, 'message' => 'Card is not active'];
        }
        
        if ($card->balance < $amount) {
            return ['success' => false, 'message' => 'Insufficient card balance'];
        }
        
        $this->load->model('Wallet_model');
        $this->load->model('Transaction_model');
        
        // Create transaction
        $transaction_id = $this->Transaction_model->create([
            'type' => 'card_withdrawal',
            'destination_wallet_id' => $destination_wallet_id,
            'amount' => $amount,
            'currency' => $card->currency,
            'narration' => 'Card withdrawal - ' . $card->card_number_masked,
            'status' => 'processing',
            'metadata' => json_encode(['card_id' => $card_id])
        ]);
        
        // Debit card
        $new_balance = $card->balance - $amount;
        $this->update($card_id, ['balance' => $new_balance]);
        
        // Credit wallet
        $this->Wallet_model->credit($destination_wallet_id, $amount);
        
        // Record card transaction
        $this->create_card_transaction([
            'card_id' => $card_id,
            'transaction_id' => $transaction_id,
            'type' => 'withdrawal',
            'amount' => $amount,
            'currency' => $card->currency,
            'status' => 'approved'
        ]);
        
        // Update main transaction status
        $this->Transaction_model->update_status($transaction_id, 'completed');
        
        return [
            'success' => true,
            'message' => 'Withdrawal successful',
            'new_balance' => $new_balance
        ];
    }

    /**
     * Create card transaction record
     */
    public function create_card_transaction($data) {
        $data['created_at'] = date('Y-m-d H:i:s');
        $this->db->insert('card_transactions', $data);
        return $this->db->insert_id();
    }

    /**
     * Get card transactions
     */
    public function get_card_transactions($card_id, $limit = 50, $offset = 0) {
        $this->db->where('card_id', $card_id);
        $this->db->order_by('created_at', 'DESC');
        $this->db->limit($limit, $offset);
        return $this->db->get('card_transactions')->result();
    }

    /**
     * Update card limits
     */
    public function update_limits($id, $limits) {
        return $this->update($id, [
            'daily_limit' => $limits['daily_limit'] ?? null,
            'monthly_limit' => $limits['monthly_limit'] ?? null,
            'single_transaction_limit' => $limits['single_transaction_limit'] ?? null
        ]);
    }

    /**
     * Update card controls
     */
    public function update_controls($id, $controls) {
        return $this->update($id, [
            'is_online_enabled' => $controls['is_online_enabled'] ?? 1,
            'is_pos_enabled' => $controls['is_pos_enabled'] ?? 1,
            'is_atm_enabled' => $controls['is_atm_enabled'] ?? 0,
            'is_international_enabled' => $controls['is_international_enabled'] ?? 0
        ]);
    }

    /**
     * Create card dispute
     */
    public function create_dispute($data) {
        $data['status'] = 'open';
        $data['created_at'] = date('Y-m-d H:i:s');
        $this->db->insert('card_disputes', $data);
        return $this->db->insert_id();
    }

    /**
     * Get user disputes
     */
    public function get_disputes($user_id, $limit = 20) {
        $this->db->select('card_disputes.*, cards.card_number_masked');
        $this->db->from('card_disputes');
        $this->db->join('cards', 'cards.id = card_disputes.card_id');
        $this->db->where('card_disputes.user_id', $user_id);
        $this->db->order_by('card_disputes.created_at', 'DESC');
        $this->db->limit($limit);
        return $this->db->get()->result();
    }

    /**
     * Generate card number (16 digits)
     */
    private function generate_card_number() {
        // Mastercard BIN prefix
        $prefix = '5399';
        $number = $prefix . str_pad(mt_rand(0, 999999999999), 12, '0', STR_PAD_LEFT);
        return substr($number, 0, 16);
    }

    /**
     * Generate expiry date
     */
    private function generate_expiry() {
        $month = str_pad(mt_rand(1, 12), 2, '0', STR_PAD_LEFT);
        $year = date('Y') + 3; // 3 years validity
        return ['month' => $month, 'year' => (string)$year];
    }

    /**
     * Generate CVV
     */
    private function generate_cvv() {
        return str_pad(mt_rand(0, 999), 3, '0', STR_PAD_LEFT);
    }

    /**
     * Encrypt sensitive data
     */
    private function encrypt_data($data) {
        $key = $this->config->item('encryption_key');
        return base64_encode(openssl_encrypt($data, 'AES-256-CBC', $key, 0, substr($key, 0, 16)));
    }

    /**
     * Decrypt sensitive data
     */
    public function decrypt_data($encrypted) {
        $key = $this->config->item('encryption_key');
        return openssl_decrypt(base64_decode($encrypted), 'AES-256-CBC', $key, 0, substr($key, 0, 16));
    }

    /**
     * Count cards
     */
    public function count_all($filters = []) {
        if (!empty($filters['status'])) {
            $this->db->where('status', $filters['status']);
        }
        if (!empty($filters['card_type'])) {
            $this->db->where('card_type', $filters['card_type']);
        }
        return $this->db->count_all_results($this->table);
    }
}
