<?php
require_once 'Database.php';
require_once 'Security.php';

class Escrow {
    private $db;
    
    public function __construct() {
        $this->db = new Database();
    }
    
    // Create escrow for a trade
    public function createEscrow($tradeId, $amount, $cryptoId) {
        try {
            $this->db->beginTransaction();
            
            // Generate unique escrow address
            $escrowAddress = $this->generateEscrowAddress($tradeId, $cryptoId);
            
            // Create escrow record
            $this->db->query("INSERT INTO escrow (trade_id, amount, status, escrow_address, created_at) 
                             VALUES (:trade_id, :amount, 'locked', :escrow_address, NOW())");
            $this->db->bind(':trade_id', $tradeId);
            $this->db->bind(':amount', $amount);
            $this->db->bind(':escrow_address', $escrowAddress);
            
            if (!$this->db->execute()) {
                throw new Exception('Failed to create escrow record');
            }
            
            $escrowId = $this->db->lastInsertId();
            
            $this->db->endTransaction();
            
            Security::logSecurityEvent('ESCROW_CREATED', "Escrow created for trade #$tradeId", null);
            
            return [
                'success' => true,
                'escrow_id' => $escrowId,
                'escrow_address' => $escrowAddress,
                'message' => 'Escrow created successfully'
            ];
            
        } catch (Exception $e) {
            $this->db->cancelTransaction();
            error_log('Create escrow error: ' . $e->getMessage());
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }
    
    // Release escrow funds to buyer
    public function releaseEscrow($tradeId, $releasedBy, $notes = null) {
        try {
            $this->db->beginTransaction();
            
            // Get escrow details
            $escrow = $this->getEscrowByTradeId($tradeId);
            if (!$escrow || $escrow['status'] !== 'locked') {
                throw new Exception('Escrow not found or already processed');
            }
            
            // Get trade details
            $this->db->query("SELECT * FROM trades WHERE id = :trade_id");
            $this->db->bind(':trade_id', $tradeId);
            $trade = $this->db->single();
            
            if (!$trade) {
                throw new Exception('Trade not found');
            }
            
            // Update escrow status
            $this->db->query("UPDATE escrow SET 
                             status = 'released', 
                             released_at = NOW(), 
                             released_by = :released_by,
                             notes = :notes
                             WHERE trade_id = :trade_id");
            $this->db->bind(':released_by', $releasedBy);
            $this->db->bind(':notes', $notes);
            $this->db->bind(':trade_id', $tradeId);
            
            if (!$this->db->execute()) {
                throw new Exception('Failed to update escrow status');
            }
            
            // Transfer funds from seller's locked balance to buyer's available balance
            $wallet = new Wallet();
            $transferResult = $wallet->transferFromEscrow(
                $trade['seller_id'],
                $trade['buyer_id'],
                $trade['crypto_id'],
                $trade['amount'],
                $tradeId
            );
            
            if (!$transferResult['success']) {
                throw new Exception($transferResult['message']);
            }
            
            $this->db->endTransaction();
            
            Security::logSecurityEvent('ESCROW_RELEASED', "Escrow released for trade #$tradeId", $releasedBy);
            
            return [
                'success' => true,
                'message' => 'Escrow funds released successfully'
            ];
            
        } catch (Exception $e) {
            $this->db->cancelTransaction();
            error_log('Release escrow error: ' . $e->getMessage());
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }
    
    // Refund escrow funds to seller (in case of dispute or cancellation)
    public function refundEscrow($tradeId, $refundedBy, $reason = null) {
        try {
            $this->db->beginTransaction();
            
            // Get escrow details
            $escrow = $this->getEscrowByTradeId($tradeId);
            if (!$escrow || $escrow['status'] !== 'locked') {
                throw new Exception('Escrow not found or already processed');
            }
            
            // Get trade details
            $this->db->query("SELECT * FROM trades WHERE id = :trade_id");
            $this->db->bind(':trade_id', $tradeId);
            $trade = $this->db->single();
            
            if (!$trade) {
                throw new Exception('Trade not found');
            }
            
            // Update escrow status
            $this->db->query("UPDATE escrow SET 
                             status = 'refunded', 
                             released_at = NOW(), 
                             released_by = :refunded_by,
                             notes = :reason
                             WHERE trade_id = :trade_id");
            $this->db->bind(':refunded_by', $refundedBy);
            $this->db->bind(':reason', $reason);
            $this->db->bind(':trade_id', $tradeId);
            
            if (!$this->db->execute()) {
                throw new Exception('Failed to update escrow status');
            }
            
            // Return funds from locked balance to seller's available balance
            $wallet = new Wallet();
            $refundResult = $wallet->unlockFunds(
                $trade['seller_id'],
                $trade['crypto_id'],
                $trade['amount']
            );
            
            if (!$refundResult['success']) {
                throw new Exception($refundResult['message']);
            }
            
            $this->db->endTransaction();
            
            Security::logSecurityEvent('ESCROW_REFUNDED', "Escrow refunded for trade #$tradeId: $reason", $refundedBy);
            
            return [
                'success' => true,
                'message' => 'Escrow funds refunded successfully'
            ];
            
        } catch (Exception $e) {
            $this->db->cancelTransaction();
            error_log('Refund escrow error: ' . $e->getMessage());
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }
    
    // Get escrow by trade ID
    public function getEscrowByTradeId($tradeId) {
        $this->db->query("SELECT e.*, t.seller_id, t.buyer_id, t.crypto_id, c.symbol, c.name
                         FROM escrow e
                         JOIN trades t ON e.trade_id = t.id
                         JOIN cryptocurrencies c ON t.crypto_id = c.id
                         WHERE e.trade_id = :trade_id");
        $this->db->bind(':trade_id', $tradeId);
        return $this->db->single();
    }
    
    // Get all escrows with optional filters
    public function getEscrows($status = null, $limit = 50) {
        $query = "SELECT e.*, t.seller_id, t.buyer_id, t.crypto_id, t.amount as trade_amount,
                         c.symbol, c.name,
                         seller.username as seller_username,
                         buyer.username as buyer_username,
                         releaser.username as released_by_username
                  FROM escrow e
                  JOIN trades t ON e.trade_id = t.id
                  JOIN cryptocurrencies c ON t.crypto_id = c.id
                  LEFT JOIN users seller ON t.seller_id = seller.id
                  LEFT JOIN users buyer ON t.buyer_id = buyer.id
                  LEFT JOIN users releaser ON e.released_by = releaser.id";
        
        if ($status) {
            $query .= " WHERE e.status = :status";
        }
        
        $query .= " ORDER BY e.created_at DESC LIMIT :limit";
        
        $this->db->query($query);
        
        if ($status) {
            $this->db->bind(':status', $status);
        }
        
        $this->db->bind(':limit', $limit);
        return $this->db->resultSet();
    }
    
    // Get escrow statistics
    public function getEscrowStats() {
        $stats = [];
        
        // Total escrows by status
        $this->db->query("SELECT status, COUNT(*) as count, SUM(amount) as total_amount 
                         FROM escrow 
                         GROUP BY status");
        $statusStats = $this->db->resultSet();
        
        foreach ($statusStats as $stat) {
            $stats['by_status'][$stat['status']] = [
                'count' => $stat['count'],
                'total_amount' => $stat['total_amount']
            ];
        }
        
        // Active escrows (locked)
        $this->db->query("SELECT COUNT(*) as count, SUM(amount) as total_amount 
                         FROM escrow 
                         WHERE status = 'locked'");
        $activeEscrow = $this->db->single();
        $stats['active'] = $activeEscrow;
        
        // Escrows created today
        $this->db->query("SELECT COUNT(*) as count 
                         FROM escrow 
                         WHERE DATE(created_at) = CURDATE()");
        $todayEscrow = $this->db->single();
        $stats['today'] = $todayEscrow['count'];
        
        // Average escrow amount
        $this->db->query("SELECT AVG(amount) as avg_amount FROM escrow");
        $avgEscrow = $this->db->single();
        $stats['average_amount'] = $avgEscrow['avg_amount'];
        
        return $stats;
    }
    
    // Check for expired escrows (should be run as cron job)
    public function processExpiredEscrows() {
        try {
            $this->db->beginTransaction();
            
            // Get escrows that have been locked for more than the timeout period
            $timeoutMinutes = TRADE_TIMEOUT; // From config
            $this->db->query("SELECT e.*, t.seller_id, t.buyer_id, t.crypto_id
                             FROM escrow e
                             JOIN trades t ON e.trade_id = t.id
                             WHERE e.status = 'locked' 
                             AND e.created_at < DATE_SUB(NOW(), INTERVAL :timeout MINUTE)");
            $this->db->bind(':timeout', $timeoutMinutes);
            $expiredEscrows = $this->db->resultSet();
            
            $processedCount = 0;
            
            foreach ($expiredEscrows as $escrow) {
                // Auto-refund expired escrows
                $refundResult = $this->refundEscrow(
                    $escrow['trade_id'],
                    null, // System refund
                    'Automatic refund due to trade timeout'
                );
                
                if ($refundResult['success']) {
                    // Update trade status to cancelled
                    $this->db->query("UPDATE trades SET status = 'cancelled' WHERE id = :trade_id");
                    $this->db->bind(':trade_id', $escrow['trade_id']);
                    $this->db->execute();
                    
                    $processedCount++;
                }
            }
            
            $this->db->endTransaction();
            
            if ($processedCount > 0) {
                Security::logSecurityEvent('ESCROW_AUTO_REFUND', "Auto-refunded $processedCount expired escrows", null);
            }
            
            return [
                'success' => true,
                'processed_count' => $processedCount,
                'message' => "Processed $processedCount expired escrows"
            ];
            
        } catch (Exception $e) {
            $this->db->cancelTransaction();
            error_log('Process expired escrows error: ' . $e->getMessage());
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }
    
    // Generate unique escrow address
    private function generateEscrowAddress($tradeId, $cryptoId) {
        $timestamp = time();
        $random = bin2hex(random_bytes(8));
        return "ESC_{$cryptoId}_{$tradeId}_{$timestamp}_{$random}";
    }
    
    // Validate escrow address format
    public function validateEscrowAddress($address) {
        return preg_match('/^ESC_\d+_\d+_\d+_[a-f0-9]{16}$/', $address);
    }
    
    // Get escrow by address
    public function getEscrowByAddress($address) {
        $this->db->query("SELECT e.*, t.seller_id, t.buyer_id, t.crypto_id, c.symbol, c.name
                         FROM escrow e
                         JOIN trades t ON e.trade_id = t.id
                         JOIN cryptocurrencies c ON t.crypto_id = c.id
                         WHERE e.escrow_address = :address");
        $this->db->bind(':address', $address);
        return $this->db->single();
    }
    
    // Emergency escrow release (admin only)
    public function emergencyRelease($tradeId, $adminId, $reason) {
        try {
            // Verify admin permissions
            $this->db->query("SELECT is_admin FROM users WHERE id = :admin_id");
            $this->db->bind(':admin_id', $adminId);
            $admin = $this->db->single();
            
            if (!$admin || !$admin['is_admin']) {
                throw new Exception('Unauthorized: Admin access required');
            }
            
            $result = $this->releaseEscrow($tradeId, $adminId, "EMERGENCY RELEASE: $reason");
            
            if ($result['success']) {
                Security::logSecurityEvent('ESCROW_EMERGENCY_RELEASE', 
                                         "Emergency release for trade #$tradeId: $reason", 
                                         $adminId);
            }
            
            return $result;
            
        } catch (Exception $e) {
            error_log('Emergency escrow release error: ' . $e->getMessage());
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }
    
    // Get escrow history for a user
    public function getUserEscrowHistory($userId, $limit = 50) {
        $this->db->query("SELECT e.*, t.seller_id, t.buyer_id, t.crypto_id, t.amount as trade_amount,
                         c.symbol, c.name,
                         CASE 
                             WHEN t.seller_id = :user_id THEN 'seller'
                             WHEN t.buyer_id = :user_id THEN 'buyer'
                             ELSE 'unknown'
                         END as user_role
                         FROM escrow e
                         JOIN trades t ON e.trade_id = t.id
                         JOIN cryptocurrencies c ON t.crypto_id = c.id
                         WHERE t.seller_id = :user_id OR t.buyer_id = :user_id
                         ORDER BY e.created_at DESC
                         LIMIT :limit");
        $this->db->bind(':user_id', $userId);
        $this->db->bind(':limit', $limit);
        return $this->db->resultSet();
    }
}
?>