<?php
final class ImportService {
    public function importUploadedXml(string $tmpPath, string $originalName): array {
        $pdo = Database::pdo();
        $safeName = date('Ymd_His') . '_' . preg_replace('/[^a-zA-Z0-9._-]+/', '_', $originalName);
        $importPath = storage_path('imports/' . $safeName);
        if (!move_uploaded_file($tmpPath, $importPath)) {
            if (!copy($tmpPath, $importPath)) throw new RuntimeException('Não foi possível salvar o XML enviado.');
        }
        $sanitized = $this->sanitizeXmlToTemp($importPath);
        $hash = hash_file('sha256', $importPath) ?: '';
        $pdo->prepare('INSERT INTO imports (filename, file_hash, status, started_at) VALUES (?, ?, ?, NOW())')
            ->execute([$originalName, $hash, 'running']);
        $importId = (int)$pdo->lastInsertId();
        $stats = ['created'=>0,'updated'=>0,'skipped'=>0,'items'=>0,'meta'=>0,'notes'=>0,'shipping'=>0,'intelligence'=>0];
        try {
            $reader = new XMLReader();
            if (!$reader->open($sanitized, 'UTF-8')) throw new RuntimeException('XML inválido ou inacessível.');
            $pdo->beginTransaction();
            while ($reader->read()) {
                if ($reader->nodeType === XMLReader::ELEMENT && $reader->name === 'Order') {
                    $xml = $reader->readOuterXML();
                    $order = simplexml_load_string($xml, SimpleXMLElement::class, LIBXML_NOCDATA | LIBXML_NONET);
                    if ($order) $this->upsertOrder($pdo, $order, $xml, $importId, $stats);
                    unset($order, $xml);
                }
            }
            $reader->close();
            $pdo->commit();
            (new OrderIntelligenceService())->clearCache();
            $pdo->prepare('UPDATE imports SET status=?, finished_at=NOW(), stats_json=? WHERE id=?')
                ->execute(['done', json_encode($stats, JSON_UNESCAPED_UNICODE), $importId]);
        } catch (Throwable $e) {
            if ($pdo->inTransaction()) $pdo->rollBack();
            $pdo->prepare('UPDATE imports SET status=?, finished_at=NOW(), error_message=? WHERE id=?')
                ->execute(['error', $e->getMessage(), $importId]);
            throw $e;
        } finally {
            if (is_file($sanitized)) @unlink($sanitized);
        }
        return ['import_id'=>$importId] + $stats;
    }
    private function sanitizeXmlToTemp(string $source): string {
        $dest = tempnam(sys_get_temp_dir(), 'wcr_xml_');
        $in = fopen($source, 'rb'); $out = fopen($dest, 'wb');
        if (!$in || !$out) throw new RuntimeException('Falha ao preparar XML.');
        $tail = ''; $stopped = false;
        while (!feof($in)) {
            $chunk = fread($in, 1024 * 1024);
            if ($chunk === false) break;
            $pos = strpos($chunk, '<!--');
            if ($pos !== false) { $chunk = substr($chunk, 0, $pos); $stopped = true; }
            fwrite($out, $chunk);
            $tail = substr($tail . $chunk, -200);
            if ($stopped) break;
        }
        fclose($in);
        if (strpos($tail, '</Orders>') === false) fwrite($out, '</Orders>');
        fclose($out);
        return $dest;
    }
    private function sx(SimpleXMLElement $e, string $tag): string { return clean_text((string)($e->{$tag} ?? '')); }
    private function upsertOrder(PDO $pdo, SimpleXMLElement $o, string $rawXml, int $importId, array &$stats): void {
        $wooId = (int)$this->sx($o,'OrderId');
        if (!$wooId) { $stats['skipped']++; return; }
        $exists = $pdo->prepare('SELECT id FROM orders WHERE woo_order_id=? LIMIT 1');
        $exists->execute([$wooId]);
        $row = $exists->fetch();
        $data = [
            $wooId, $this->sx($o,'OrderNumber'), $this->sx($o,'OrderNumberFormatted'), $this->sx($o,'OrderDate'), $this->sx($o,'OrderStatus'), $this->sx($o,'OrderCurrency'),
            $this->sx($o,'BillingFullName'), $this->sx($o,'BillingEmail'), $this->sx($o,'BillingPhone'), $this->sx($o,'BillingCity'), $this->sx($o,'BillingState'), $this->sx($o,'BillingPostcode'), $this->sx($o,'BillingCountry'),
            $this->sx($o,'ShippingFullName'), $this->sx($o,'ShippingCity'), $this->sx($o,'ShippingState'), $this->sx($o,'ShippingPostcode'), $this->sx($o,'ShippingMethodId'), $this->sx($o,'ShippingMethod'),
            $this->sx($o,'PaymentMethodId'), $this->sx($o,'PaymentMethod'), money_float($this->sx($o,'DiscountTotal')), money_float($this->sx($o,'ShippingTotal')), money_float($this->sx($o,'OrderTotal')), money_float($this->sx($o,'RefundedTotal')), $this->sx($o,'CustomerNote'), (int)$this->sx($o,'CustomerId'), $this->sx($o,'CompletedDate') ?: null, $rawXml, $importId
        ];
        if ($row) {
            $orderId = (int)$row['id'];
            $sql = 'UPDATE orders SET order_number=?, order_number_formatted=?, order_date=?, status=?, currency=?, billing_name=?, billing_email=?, billing_phone=?, billing_city=?, billing_state=?, billing_postcode=?, billing_country=?, shipping_name=?, shipping_city=?, shipping_state=?, shipping_postcode=?, shipping_method_id=?, shipping_method=?, payment_method_id=?, payment_method=?, discount_total=?, shipping_total=?, order_total=?, refunded_total=?, customer_note=?, customer_id=?, completed_date=?, raw_xml=?, import_id=?, updated_at=NOW() WHERE id=?';
            $pdo->prepare($sql)->execute(array_merge(array_slice($data,1), [$orderId]));
            $pdo->prepare('DELETE FROM order_items WHERE order_id=?')->execute([$orderId]);
            $pdo->prepare('DELETE FROM order_notes WHERE order_id=?')->execute([$orderId]);
            $pdo->prepare('DELETE FROM shipping_items WHERE order_id=?')->execute([$orderId]);
            $stats['updated']++;
        } else {
            $sql = 'INSERT INTO orders (woo_order_id, order_number, order_number_formatted, order_date, status, currency, billing_name, billing_email, billing_phone, billing_city, billing_state, billing_postcode, billing_country, shipping_name, shipping_city, shipping_state, shipping_postcode, shipping_method_id, shipping_method, payment_method_id, payment_method, discount_total, shipping_total, order_total, refunded_total, customer_note, customer_id, completed_date, raw_xml, import_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)';
            $pdo->prepare($sql)->execute($data);
            $orderId = (int)$pdo->lastInsertId();
            $stats['created']++;
        }
        foreach (($o->OrderLineItems->OrderLineItem ?? []) as $li) $this->insertItem($pdo, $orderId, $li, $stats);
        foreach (($o->OrderNotes->OrderNote ?? []) as $note) {
            $pdo->prepare('INSERT INTO order_notes (order_id, note_date, author, content) VALUES (?,?,?,?)')->execute([$orderId, $this->sx($note,'Date'), $this->sx($note,'Author'), $this->sx($note,'Content')]);
            $stats['notes']++;
        }
        foreach (($o->ShippingItems->ShippingItem ?? []) as $ship) {
            $pdo->prepare('INSERT INTO shipping_items (order_id, woo_shipping_id, method_id, method_name, total) VALUES (?,?,?,?,?)')->execute([$orderId, (int)$this->sx($ship,'Id'), $this->sx($ship,'MethodId'), $this->sx($ship,'MethodName'), money_float($this->sx($ship,'Total'))]);
            $stats['shipping']++;
        }
        (new OrderIntelligenceService())->analyzeOrder($orderId);
        $stats['intelligence']++;
    }
    private function insertItem(PDO $pdo, int $orderId, SimpleXMLElement $li, array &$stats): void {
        $metaRaw = $this->sx($li,'Meta');
        $pdo->prepare('INSERT INTO order_items (order_id, woo_item_id, product_id, sku, name, quantity, price, subtotal, total, refunded, refunded_quantity, meta_raw) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)')
            ->execute([$orderId, (int)$this->sx($li,'Id'), (int)$this->sx($li,'ProductId'), $this->sx($li,'SKU'), $this->sx($li,'Name'), (float)$this->sx($li,'Quantity'), money_float($this->sx($li,'Price')), money_float($this->sx($li,'Subtotal')), money_float($this->sx($li,'Total')), money_float($this->sx($li,'Refunded')), (int)$this->sx($li,'RefundedQuantity'), $metaRaw]);
        $itemId = (int)$pdo->lastInsertId(); $stats['items']++;
        foreach ($this->parseMeta($metaRaw) as $k=>$v) {
            $pdo->prepare('INSERT INTO order_item_meta (order_item_id, meta_key, normalized_key, meta_value) VALUES (?,?,?,?)')->execute([$itemId, $k, normalize_key($k), $v]);
            $stats['meta']++;
        }
    }
    private function parseMeta(string $raw): array {
        $raw = trim($raw); if ($raw==='') return [];
        $parts = preg_split('/,\s+(?=[^,]{0,90}:)/u', $raw) ?: [];
        $out = [];
        foreach ($parts as $part) {
            $pos = strpos($part, ':');
            if ($pos === false) continue;
            $k = trim(substr($part,0,$pos)); $v = trim(substr($part,$pos+1));
            if ($k === '') $k = 'Campo sem rótulo';
            if ($v === '') continue;
            if (isset($out[$k])) $out[$k] .= ' | ' . $v; else $out[$k] = $v;
        }
        return $out;
    }
}
