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

class Wallet_model extends CI_Model {

    protected $table = 'wallets';

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

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

    /**
     * Get wallet by account and currency
     */
    public function get_by_account($account_id, $currency = 'USD') {
        return $this->db->get_where($this->table, [
            'account_id' => $account_id,
            'currency' => $currency
        ])->row();
    }

    /**
     * Get all wallets for an account
     */
    public function get_all_by_account($account_id) {
        return $this->db->get_where($this->table, ['account_id' => $account_id])->result();
    }

    /**
     * Create wallet
     */
    public function create($data) {
        $data['ledger_balance'] = $data['ledger_balance'] ?? 0;
        $data['available_balance'] = $data['available_balance'] ?? 0;
        $data['pending_credits'] = 0;
        $data['pending_debits'] = 0;
        $data['locked_amount'] = 0;
        $data['created_at'] = date('Y-m-d H:i:s');
        
        $this->db->insert($this->table, $data);
        return $this->db->insert_id();
    }

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

    /**
     * Credit wallet (add money)
     */
    public function credit($wallet_id, $amount, $update_ledger = true) {
        $wallet = $this->get($wallet_id);
        if (!$wallet) return false;
        
        $update_data = [
            'available_balance' => $wallet->available_balance + $amount,
            'updated_at' => date('Y-m-d H:i:s')
        ];
        
        if ($update_ledger) {
            $update_data['ledger_balance'] = $wallet->ledger_balance + $amount;
        }
        
        return $this->db->update($this->table, $update_data, ['id' => $wallet_id]);
    }

    /**
     * Debit wallet (remove money)
     */
    public function debit($wallet_id, $amount, $update_ledger = true) {
        $wallet = $this->get($wallet_id);
        if (!$wallet) return false;
        
        // Check sufficient balance
        if ($wallet->available_balance < $amount) {
            return false;
        }
        
        $update_data = [
            'available_balance' => $wallet->available_balance - $amount,
            'updated_at' => date('Y-m-d H:i:s')
        ];
        
        if ($update_ledger) {
            $update_data['ledger_balance'] = $wallet->ledger_balance - $amount;
        }
        
        return $this->db->update($this->table, $update_data, ['id' => $wallet_id]);
    }

    /**
     * Check if wallet has sufficient balance
     */
    public function has_sufficient_balance($wallet_id, $amount) {
        $wallet = $this->get($wallet_id);
        return $wallet && $wallet->available_balance >= $amount;
    }

    /**
     * Place hold on funds
     */
    public function place_hold($wallet_id, $amount, $transaction_id = null, $reason = null, $expires_at = null) {
        $wallet = $this->get($wallet_id);
        if (!$wallet || $wallet->available_balance < $amount) {
            return false;
        }
        
        // Reduce available balance
        $this->db->update($this->table, [
            'available_balance' => $wallet->available_balance - $amount,
            'locked_amount' => $wallet->locked_amount + $amount,
            'updated_at' => date('Y-m-d H:i:s')
        ], ['id' => $wallet_id]);
        
        // Create hold record
        $this->db->insert('transaction_holds', [
            'wallet_id' => $wallet_id,
            'transaction_id' => $transaction_id,
            'amount' => $amount,
            'reason' => $reason,
            'status' => 'active',
            'expires_at' => $expires_at,
            'created_at' => date('Y-m-d H:i:s')
        ]);
        
        return $this->db->insert_id();
    }

    /**
     * Release hold
     */
    public function release_hold($hold_id) {
        $hold = $this->db->get_where('transaction_holds', ['id' => $hold_id])->row();
        if (!$hold || $hold->status !== 'active') {
            return false;
        }
        
        $wallet = $this->get($hold->wallet_id);
        if (!$wallet) return false;
        
        // Return funds to available balance
        $this->db->update($this->table, [
            'available_balance' => $wallet->available_balance + $hold->amount,
            'locked_amount' => $wallet->locked_amount - $hold->amount,
            'updated_at' => date('Y-m-d H:i:s')
        ], ['id' => $hold->wallet_id]);
        
        // Update hold status
        $this->db->update('transaction_holds', [
            'status' => 'released',
            'released_at' => date('Y-m-d H:i:s')
        ], ['id' => $hold_id]);
        
        return true;
    }

    /**
     * Capture hold (complete the transaction)
     */
    public function capture_hold($hold_id) {
        $hold = $this->db->get_where('transaction_holds', ['id' => $hold_id])->row();
        if (!$hold || $hold->status !== 'active') {
            return false;
        }
        
        $wallet = $this->get($hold->wallet_id);
        if (!$wallet) return false;
        
        // Deduct from ledger balance and locked amount
        $this->db->update($this->table, [
            'ledger_balance' => $wallet->ledger_balance - $hold->amount,
            'locked_amount' => $wallet->locked_amount - $hold->amount,
            'updated_at' => date('Y-m-d H:i:s')
        ], ['id' => $hold->wallet_id]);
        
        // Update hold status
        $this->db->update('transaction_holds', [
            'status' => 'captured',
            'released_at' => date('Y-m-d H:i:s')
        ], ['id' => $hold_id]);
        
        return true;
    }

    /**
     * Get active holds for wallet
     */
    public function get_active_holds($wallet_id) {
        return $this->db->get_where('transaction_holds', [
            'wallet_id' => $wallet_id,
            'status' => 'active'
        ])->result();
    }

    /**
     * Create ledger entry
     */
    public function create_ledger_entry($data) {
        $data['created_at'] = date('Y-m-d H:i:s');
        $this->db->insert('ledger_entries', $data);
        return $this->db->insert_id();
    }

    /**
     * Get ledger entries for wallet
     */
    public function get_ledger_entries($wallet_id, $limit = 50, $offset = 0) {
        $this->db->where('wallet_id', $wallet_id);
        $this->db->order_by('created_at', 'DESC');
        $this->db->limit($limit, $offset);
        return $this->db->get('ledger_entries')->result();
    }

    /**
     * Transfer between wallets (atomic operation)
     */
    public function transfer($source_wallet_id, $destination_wallet_id, $amount, $transaction_id) {
        $this->db->trans_start();
        
        $source_wallet = $this->get($source_wallet_id);
        $dest_wallet = $this->get($destination_wallet_id);
        
        if (!$source_wallet || !$dest_wallet) {
            $this->db->trans_rollback();
            return ['success' => false, 'message' => 'Invalid wallet'];
        }
        
        if ($source_wallet->available_balance < $amount) {
            $this->db->trans_rollback();
            return ['success' => false, 'message' => 'Insufficient balance'];
        }
        
        // Debit source
        $source_new_balance = $source_wallet->ledger_balance - $amount;
        $this->db->update($this->table, [
            'ledger_balance' => $source_new_balance,
            'available_balance' => $source_wallet->available_balance - $amount,
            'updated_at' => date('Y-m-d H:i:s')
        ], ['id' => $source_wallet_id]);
        
        // Create debit ledger entry
        $this->create_ledger_entry([
            'transaction_id' => $transaction_id,
            'wallet_id' => $source_wallet_id,
            'entry_type' => 'debit',
            'amount' => $amount,
            'balance_before' => $source_wallet->ledger_balance,
            'balance_after' => $source_new_balance,
            'description' => 'Transfer out'
        ]);
        
        // Credit destination
        $dest_new_balance = $dest_wallet->ledger_balance + $amount;
        $this->db->update($this->table, [
            'ledger_balance' => $dest_new_balance,
            'available_balance' => $dest_wallet->available_balance + $amount,
            'updated_at' => date('Y-m-d H:i:s')
        ], ['id' => $destination_wallet_id]);
        
        // Create credit ledger entry
        $this->create_ledger_entry([
            'transaction_id' => $transaction_id,
            'wallet_id' => $destination_wallet_id,
            'entry_type' => 'credit',
            'amount' => $amount,
            'balance_before' => $dest_wallet->ledger_balance,
            'balance_after' => $dest_new_balance,
            'description' => 'Transfer in'
        ]);
        
        $this->db->trans_complete();
        
        if ($this->db->trans_status() === FALSE) {
            return ['success' => false, 'message' => 'Transfer failed'];
        }
        
        return ['success' => true, 'message' => 'Transfer successful'];
    }
}
