<?php
/**
 * ManualShippingProvider
 * 
 * Provedor de frete baseado em tabela manual (faixas de CEP).
 * Usa ShippingCalculator para cálculo correto de peso volumétrico.
 * 
 * @package Shipping\Providers
 */

namespace Shipping\Providers;

require_once __DIR__ . '/../ShippingCalculator.php';

use Shipping\ShippingCalculator;

class ManualShippingProvider implements ShippingProviderInterface
{
    private \PDO $pdo;
    private int $storeId;
    private ShippingCalculator $calculator;
    
    public function __construct(\PDO $pdo, int $storeId)
    {
        $this->pdo = $pdo;
        $this->storeId = $storeId;
        $this->calculator = new ShippingCalculator();
    }
    
    /**
     * {@inheritdoc}
     */
    public function calculateShipping(
        array $items,
        string $originZipcode,
        string $destinationZipcode,
        int $storeId
    ): array {
        $options = [];
        $destinationClean = preg_replace('/\D/', '', $destinationZipcode);
        
        // Usar ShippingCalculator para calcular peso correto (real vs volumétrico)
        $weightData = $this->calculator->calculateTotalWeight($items);
        $billableWeight = $weightData['billable_weight']; // Maior entre real e volumétrico
        $totalRealWeight = $weightData['weight'];
        $volumetricWeight = $weightData['volumetric_weight'];
        
        // Buscar métodos de frete manual ativos
        $stmt = $this->pdo->prepare("
            SELECT sm.id, sm.name, sm.additional_days, sm.additional_cost, sm.min_order_value, sm.config
            FROM shipping_methods sm
            WHERE sm.store_id = ? 
              AND sm.type = 'manual' 
              AND sm.is_active = 1
            ORDER BY sm.priority ASC
        ");
        $stmt->execute([$storeId]);
        $methods = $stmt->fetchAll(\PDO::FETCH_ASSOC);
        
        foreach ($methods as $method) {
            // Buscar zona que atende o CEP de destino
            $zoneStmt = $this->pdo->prepare("
                SELECT * FROM shipping_zones
                WHERE store_id = ? 
                  AND shipping_method_id = ?
                  AND is_active = 1
                  AND ? BETWEEN zipcode_start AND zipcode_end
                ORDER BY price ASC
                LIMIT 1
            ");
            $zoneStmt->execute([$storeId, $method['id'], $destinationClean]);
            $zone = $zoneStmt->fetch(\PDO::FETCH_ASSOC);
            
            if ($zone) {
                // Verificar limite de peso usando BILLABLE WEIGHT (maior entre real e volumétrico)
                if ($zone['max_weight'] && $billableWeight > $zone['max_weight']) {
                    continue; // Excede peso máximo dessa zona
                }
                
                // Calcular preço base da zona
                $price = floatval($zone['price']);
                
                // Adicionar custo extra por kg excedente (se configurado)
                $config = $method['config'] ? json_decode($method['config'], true) : [];
                if (isset($config['extra_per_kg']) && $config['extra_per_kg'] > 0) {
                    $baseWeight = floatval($config['base_weight'] ?? 1); // Peso base incluído no preço
                    if ($billableWeight > $baseWeight) {
                        $extraKg = $billableWeight - $baseWeight;
                        $price += $extraKg * floatval($config['extra_per_kg']);
                    }
                }
                
                // Adicionar custo adicional do método
                $price += floatval($method['additional_cost']);
                
                $minDays = intval($zone['min_days']) + intval($method['additional_days']);
                $maxDays = intval($zone['max_days']) + intval($method['additional_days']);
                
                $options[] = [
                    'id' => $method['id'],
                    'carrier' => $method['name'],
                    'service' => $zone['name'],
                    'price' => round($price, 2),
                    'delivery_time' => $minDays === $maxDays 
                        ? "{$minDays} dia(s)" 
                        : "{$minDays} a {$maxDays} dias",
                    'min_days' => $minDays,
                    'max_days' => $maxDays,
                    'free_shipping_above' => $method['min_order_value'],
                    // Informações extras para debug/exibição
                    'weight_info' => [
                        'real' => $totalRealWeight,
                        'volumetric' => $volumetricWeight,
                        'billable' => $billableWeight,
                        'unit' => 'kg'
                    ]
                ];
            }
        }
        
        return $options;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getProviderName(): string
    {
        return 'manual';
    }
    
    /**
     * {@inheritdoc}
     */
    public function isAvailable(): bool
    {
        $stmt = $this->pdo->prepare("
            SELECT COUNT(*) FROM shipping_methods 
            WHERE store_id = ? AND type = 'manual' AND is_active = 1
        ");
        $stmt->execute([$this->storeId]);
        return $stmt->fetchColumn() > 0;
    }
}
