<?php
/**
 * DisputeService - Manages order disputes
 * Location: app/Services/DisputeService.php
 */
class DisputeService {
    private $db;
    
    public function __construct() {
        $this->db = Database::getInstance()->getConnection();
    }
    
    /**
     * Raise a dispute
     */
    public function raiseDispute($order_id, $user_id, $user_type, $dispute_data) {
        $this->db->begin_transaction();
        
        try {
            // Validate order exists
            $stmt = $this->db->prepare("SELECT id, security_deposit_status FROM orders WHERE id = ?");
            $stmt->bind_param("i", $order_id);
            $stmt->execute();
            $order = $stmt->get_result()->fetch_assoc();
            
            if (!$order) {
                throw new Exception("Order not found");
            }
            
            // Check if dispute already exists
            $stmt = $this->db->prepare("
                SELECT id FROM disputes 
                WHERE order_id = ? AND status IN ('open', 'under_review')
            ");
            $stmt->bind_param("i", $order_id);
            $stmt->execute();
            if ($stmt->get_result()->num_rows > 0) {
                throw new Exception("An active dispute already exists for this order");
            }
            
            // Create dispute
            $stmt = $this->db->prepare("
                INSERT INTO disputes 
                (order_id, raised_by, raised_by_type, dispute_type, description, amount_involved, evidence_files) 
                VALUES (?, ?, ?, ?, ?, ?, ?)
            ");
            $stmt->bind_param(
                "iisssds",
                $order_id,
                $user_id,
                $user_type,
                $dispute_data['type'],
                $dispute_data['description'],
                $dispute_data['amount'] ?? null,
                $dispute_data['evidence_files'] ?? null
            );
            $stmt->execute();
            
            // Update order security deposit status
            $stmt = $this->db->prepare("
                UPDATE orders 
                SET security_deposit_status = 'disputed' 
                WHERE id = ?
            ");
            $stmt->bind_param("i", $order_id);
            $stmt->execute();
            
            $this->db->commit();
            return ['success' => true, 'dispute_id' => $this->db->insert_id];
            
        } catch (Exception $e) {
            $this->db->rollback();
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
    
    /**
     * Resolve dispute
     */
    public function resolveDispute($dispute_id, $admin_id, $resolution_data) {
        $this->db->begin_transaction();
        
        try {
            // Get dispute details
            $dispute = $this->getDisputeById($dispute_id);
            
            if (!$dispute || !in_array($dispute['status'], ['open', 'under_review'])) {
                throw new Exception("Invalid or already resolved dispute");
            }
            
            // Update dispute status
            $stmt = $this->db->prepare("
                UPDATE disputes 
                SET status = 'resolved', 
                    resolution = ?, 
                    resolved_by = ?, 
                    resolved_at = NOW() 
                WHERE id = ?
            ");
            $stmt->bind_param("sii", $resolution_data['resolution'], $admin_id, $dispute_id);
            $stmt->execute();
            
            // Handle fund distribution based on resolution
            if (isset($resolution_data['refund_to_customer']) && $resolution_data['refund_to_customer'] > 0) {
                $this->processDamageRefund(
                    $dispute['order_id'],
                    $resolution_data['refund_to_customer'],
                    $resolution_data['resolution']
                );
            }
            
            // Update order security deposit status
            $stmt = $this->db->prepare("
                UPDATE orders 
                SET security_deposit_status = 'released' 
                WHERE id = ?
            ");
            $stmt->bind_param("i", $dispute['order_id']);
            $stmt->execute();
            
            $this->db->commit();
            return ['success' => true];
            
        } catch (Exception $e) {
            $this->db->rollback();
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
    
    /**
     * Process damage/loss deduction from security deposit
     */
    private function processDamageRefund($order_id, $refund_amount, $reason) {
        // Get order details
        $stmt = $this->db->prepare("
            SELECT customer_id, vendor_id, security_deposit 
            FROM orders 
            WHERE id = ?
        ");
        $stmt->bind_param("i", $order_id);
        $stmt->execute();
        $order = $stmt->get_result()->fetch_assoc();
        
        $deduction = $order['security_deposit'] - $refund_amount;
        
        // Move deduction to vendor's main wallet
        if ($deduction > 0) {
            $walletService = new WalletService();
            $customer_held = $walletService->getWallet($order['customer_id'], 'security_held');
            $vendor_main = $walletService->getWallet($order['vendor_id'], 'main_balance');
            
            // Deduct from customer held
            $stmt = $this->db->prepare("
                UPDATE user_wallets 
                SET balance = balance - ? 
                WHERE id = ?
            ");
            $stmt->bind_param("di", $deduction, $customer_held['id']);
            $stmt->execute();
            
            // Credit vendor
            $stmt = $this->db->prepare("
                UPDATE user_wallets 
                SET balance = balance + ? 
                WHERE id = ?
            ");
            $stmt->bind_param("di", $deduction, $vendor_main['id']);
            $stmt->execute();
            
            // Record transaction
            $walletService->recordTransaction([
                'user_id' => $order['vendor_id'],
                'from_wallet_id' => $customer_held['id'],
                'to_wallet_id' => $vendor_main['id'],
                'order_id' => $order_id,
                'transaction_type' => 'dispute_deduction',
                'amount' => $deduction,
                'balance_before' => 0,
                'balance_after' => 0,
                'description' => "Dispute resolution: {$reason}",
                'reference' => 'DISPUTE_' . $order_id . '_' . time(),
                'status' => 'completed'
            ]);
        }
        
        // Refund remaining to customer's refundable wallet
        if ($refund_amount > 0) {
            $walletService = new WalletService();
            $customer_held = $walletService->getWallet($order['customer_id'], 'security_held');
            $customer_refundable = $walletService->getWallet($order['customer_id'], 'security_refundable');
            
            // Transfer from held to refundable
            $stmt = $this->db->prepare("
                UPDATE user_wallets 
                SET balance = balance - ? 
                WHERE id = ?
            ");
            $stmt->bind_param("di", $refund_amount, $customer_held['id']);
            $stmt->execute();
            
            $stmt = $this->db->prepare("
                UPDATE user_wallets 
                SET balance = balance + ? 
                WHERE id = ?
            ");
            $stmt->bind_param("di", $refund_amount, $customer_refundable['id']);
            $stmt->execute();
        }
    }
    
    /**
     * Update dispute status
     */
    public function updateStatus($dispute_id, $status) {
        $allowed_statuses = ['open', 'under_review', 'resolved', 'closed'];
        
        if (!in_array($status, $allowed_statuses)) {
            return ['success' => false, 'error' => 'Invalid status'];
        }
        
        $stmt = $this->db->prepare("
            UPDATE disputes 
            SET status = ? 
            WHERE id = ?
        ");
        $stmt->bind_param("si", $status, $dispute_id);
        
        if ($stmt->execute()) {
            return ['success' => true];
        }
        
        return ['success' => false, 'error' => 'Failed to update dispute'];
    }
    
    /**
     * Get dispute by ID
     */
    public function getDisputeById($dispute_id) {
        $stmt = $this->db->prepare("
            SELECT d.*, 
                   o.order_number, o.total_amount, o.security_deposit,
                   u.email as raised_by_email,
                   c.full_name as customer_name,
                   v.full_name as vendor_name
            FROM disputes d
            JOIN orders o ON d.order_id = o.id
            JOIN users u ON d.raised_by = u.id
            LEFT JOIN customers c ON o.customer_id = c.user_id
            LEFT JOIN vendors v ON o.vendor_id = v.user_id
            WHERE d.id = ?
        ");
        $stmt->bind_param("i", $dispute_id);
        $stmt->execute();
        return $stmt->get_result()->fetch_assoc();
    }
    
    /**
     * Get all disputes (for admin)
     */
    public function getAllDisputes($status = null, $limit = 50) {
        if ($status) {
            $stmt = $this->db->prepare("
                SELECT d.*, o.order_number, u.email as raised_by_email
                FROM disputes d
                JOIN orders o ON d.order_id = o.id
                JOIN users u ON d.raised_by = u.id
                WHERE d.status = ?
                ORDER BY d.created_at DESC
                LIMIT ?
            ");
            $stmt->bind_param("si", $status, $limit);
        } else {
            $stmt = $this->db->prepare("
                SELECT d.*, o.order_number, u.email as raised_by_email
                FROM disputes d
                JOIN orders o ON d.order_id = o.id
                JOIN users u ON d.raised_by = u.id
                ORDER BY d.created_at DESC
                LIMIT ?
            ");
            $stmt->bind_param("i", $limit);
        }
        
        $stmt->execute();
        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    }
    
    /**
     * Get user disputes
     */
    public function getUserDisputes($user_id, $limit = 20) {
        $stmt = $this->db->prepare("
            SELECT d.*, o.order_number
            FROM disputes d
            JOIN orders o ON d.order_id = o.id
            WHERE d.raised_by = ?
            ORDER BY d.created_at DESC
            LIMIT ?
        ");
        $stmt->bind_param("ii", $user_id, $limit);
        $stmt->execute();
        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    }
}
