<?php
/**
 * MelhorEnvioProvider
 * 
 * Provedor de frete integrado com a API do Melhor Envio.
 * Calcula frete automaticamente via múltiplas transportadoras.
 * 
 * API Docs: https://docs.melhorenvio.com.br/
 * 
 * @package Shipping\Providers
 */

namespace Shipping\Providers;

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

use Shipping\ShippingCalculator;

class MelhorEnvioProvider implements ShippingProviderInterface
{
    private \PDO $pdo;
    private int $storeId;
    private ShippingCalculator $calculator;
    private ?string $accessToken = null;
    private bool $sandboxMode = false;
    
    // URLs da API
    private const SANDBOX_URL = 'https://sandbox.melhorenvio.com.br/api/v2';
    private const PRODUCTION_URL = 'https://melhorenvio.com.br/api/v2';
    
    // IDs dos serviços (Melhor Envio)
    private const SERVICES = [
        // Correios
        1 => ['name' => 'PAC', 'carrier' => 'Correios'],
        2 => ['name' => 'SEDEX', 'carrier' => 'Correios'],
        3 => ['name' => 'Mini Envios', 'carrier' => 'Correios'],
        // Jadlog
        4 => ['name' => '.Package', 'carrier' => 'Jadlog'],
        5 => ['name' => '.Com', 'carrier' => 'Jadlog'],
        // Via Brasil (Rodoviário)
        9 => ['name' => 'Rodoviário', 'carrier' => 'Via Brasil'],
        // Azul Cargo
        15 => ['name' => 'Amanhã', 'carrier' => 'Azul Cargo'],
        16 => ['name' => 'E-commerce', 'carrier' => 'Azul Cargo'],
        // Latam
        17 => ['name' => 'Juntos', 'carrier' => 'LATAM Cargo'],
    ];
    
    public function __construct(\PDO $pdo, int $storeId)
    {
        $this->pdo = $pdo;
        $this->storeId = $storeId;
        $this->calculator = new ShippingCalculator();
        $this->loadCredentials();
    }
    
    /**
     * Carrega credenciais da integração do banco
     */
    private function loadCredentials(): void
    {
        $stmt = $this->pdo->prepare("
            SELECT api_token, sandbox_mode 
            FROM shipping_integrations 
            WHERE store_id = ? AND provider = 'melhor_envio' AND is_active = 1
            LIMIT 1
        ");
        $stmt->execute([$this->storeId]);
        $integration = $stmt->fetch(\PDO::FETCH_ASSOC);
        
        if ($integration) {
            $this->accessToken = $integration['api_token'];
            $this->sandboxMode = (bool)$integration['sandbox_mode'];
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function calculateShipping(
        array $items,
        string $originZipcode,
        string $destinationZipcode,
        int $storeId
    ): array {
        if (!$this->accessToken) {
            return [];
        }
        
        // Calcular peso e dimensões
        $weightData = $this->calculator->calculateTotalWeight($items);
        $boxData = $this->calculator->calculateVirtualBox($items);
        
        // Preparar payload para API
        $payload = [
            'from' => ['postal_code' => preg_replace('/\D/', '', $originZipcode)],
            'to' => ['postal_code' => preg_replace('/\D/', '', $destinationZipcode)],
            'products' => [[
                'id' => 'package',
                'width' => max(11, $boxData['width']),    // Mínimo 11cm
                'height' => max(2, $boxData['height']),   // Mínimo 2cm
                'length' => max(16, $boxData['length']),  // Mínimo 16cm
                'weight' => max(0.1, $weightData['billable_weight']), // Mínimo 100g
                'insurance_value' => 0,
                'quantity' => 1
            ]],
            'options' => [
                'receipt' => false,
                'own_hand' => false,
                'collect' => false
            ]
        ];
        
        // Fazer requisição
        $response = $this->makeRequest('/me/shipment/calculate', $payload);
        
        if (!$response || !is_array($response)) {
            return [];
        }
        
        // Processar resposta
        $options = [];
        foreach ($response as $quote) {
            // Pular se tem erro ou não tem preço
            if (isset($quote['error']) || !isset($quote['price']) || $quote['price'] <= 0) {
                continue;
            }
            
            $serviceId = $quote['id'] ?? 0;
            $serviceInfo = self::SERVICES[$serviceId] ?? ['name' => $quote['name'] ?? 'Entrega', 'carrier' => $quote['company']['name'] ?? 'Transportadora'];
            
            $deliveryMin = intval($quote['delivery_time'] ?? 1);
            $deliveryMax = intval($quote['delivery_range']['max'] ?? $deliveryMin + 2);
            
            // Adicionar tempo de manuseio da loja
            $handlingTime = $this->getStoreHandlingTime();
            $deliveryMin += $handlingTime;
            $deliveryMax += $handlingTime;
            
            $options[] = [
                'id' => 'me_' . $serviceId,
                'carrier' => $serviceInfo['carrier'],
                'service' => $serviceInfo['name'],
                'price' => round(floatval($quote['price']), 2),
                'delivery_time' => $deliveryMin === $deliveryMax 
                    ? "{$deliveryMin} dia(s) úteis" 
                    : "{$deliveryMin} a {$deliveryMax} dias úteis",
                'min_days' => $deliveryMin,
                'max_days' => $deliveryMax,
                'weight_info' => [
                    'real' => $weightData['weight'],
                    'volumetric' => $weightData['volumetric_weight'],
                    'billable' => $weightData['billable_weight'],
                    'unit' => 'kg'
                ],
                'provider' => 'melhor_envio',
                'service_id' => $serviceId
            ];
        }
        
        // Ordenar por preço
        usort($options, fn($a, $b) => $a['price'] <=> $b['price']);
        
        return $options;
    }
    
    /**
     * Faz requisição à API do Melhor Envio
     */
    private function makeRequest(string $endpoint, array $data): ?array
    {
        $baseUrl = $this->sandboxMode ? self::SANDBOX_URL : self::PRODUCTION_URL;
        $url = $baseUrl . $endpoint;
        
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($data),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Accept: application/json',
                'Authorization: Bearer ' . $this->accessToken,
                'User-Agent: DuoLead/1.0'
            ]
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error || $httpCode >= 400) {
            error_log("MelhorEnvio API Error: HTTP $httpCode - $error - Response: $response");
            return null;
        }
        
        return json_decode($response, true);
    }
    
    /**
     * Busca tempo de manuseio da loja
     */
    private function getStoreHandlingTime(): int
    {
        $stmt = $this->pdo->prepare("SELECT handling_time FROM stores WHERE id = ?");
        $stmt->execute([$this->storeId]);
        return intval($stmt->fetchColumn() ?: 0);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getProviderName(): string
    {
        return 'melhor_envio';
    }
    
    /**
     * {@inheritdoc}
     */
    public function isAvailable(): bool
    {
        return !empty($this->accessToken);
    }
    
    /**
     * Testa a conexão com a API
     */
    public function testConnection(): array
    {
        if (!$this->accessToken) {
            return ['success' => false, 'error' => 'Token não configurado'];
        }
        
        // Teste simples de cotação
        $testPayload = [
            'from' => ['postal_code' => '01310100'], // Av Paulista
            'to' => ['postal_code' => '22041080'],   // Copacabana
            'products' => [[
                'id' => 'test',
                'width' => 11, 'height' => 2, 'length' => 16,
                'weight' => 0.3, 'insurance_value' => 0, 'quantity' => 1
            ]]
        ];
        
        $response = $this->makeRequest('/me/shipment/calculate', $testPayload);
        
        if ($response && is_array($response) && count($response) > 0) {
            return [
                'success' => true, 
                'message' => 'Conexão OK - ' . count($response) . ' transportadoras disponíveis',
                'carriers' => array_column($response, 'name')
            ];
        }
        
        return ['success' => false, 'error' => 'Falha ao conectar com a API'];
    }
}
