<?php

namespace WMS\Controllers;

use WMS\Core\Database;
use WMS\Core\Request;
use WMS\Core\Response;
use WMS\Core\HanaDatabase;
use WMS\Integrations\Sap\HanaQueryService;
use WMS\Integrations\Sap\SapServiceLayerClient;

class SapController
{
    /**
     * GET /api/sap/purchase-orders
     * Lista órdenes de compra abiertas desde HANA.
     */
    public static function purchaseOrders(array $params): void
    {
        try {
            try {
                $hana = new HanaQueryService();
                $orders = $hana->getOpenPurchaseOrders();
            } catch (\Throwable $e) {
                $sl = new SapServiceLayerClient();
                $sl->login();
                $r = $sl->getOpenPurchaseOrders();
                $orders = $r['value'] ?? $r;
                $sl->logout();
            }
            Response::success($orders);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * GET /api/sap/purchase-orders/{docEntry}/lines
     * Líneas de una orden de compra desde HANA.
     */
    public static function purchaseOrderLines(array $params): void
    {
        try {
            $docEntry = (int) $params['docEntry'];
            try {
                $hana = new HanaQueryService();
                $lines = $hana->getPurchaseOrderLines($docEntry);
            } catch (\Throwable $e) {
                $sl = new SapServiceLayerClient();
                $sl->login();
                $doc = $sl->getPurchaseOrder($docEntry);
                $lines = $doc['DocumentLines'] ?? [];
                $sl->logout();
            }
            Response::success($lines);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * GET /api/sap/sales-orders
     * Lista pedidos de venta abiertos desde HANA.
     */
    public static function salesOrders(array $params): void
    {
        try {
            try {
                $hana = new HanaQueryService();
                $orders = $hana->getOpenSalesOrders();
            } catch (\Throwable $e) {
                $sl = new SapServiceLayerClient();
                $sl->login();
                $r = $sl->getOpenSalesOrders();
                $orders = $r['value'] ?? $r;
                $sl->logout();
            }
            Response::success($orders);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * GET /api/sap/sales-orders/{docEntry}/lines
     * Líneas de un pedido de venta desde HANA.
     */
    public static function salesOrderLines(array $params): void
    {
        try {
            $docEntry = (int) $params['docEntry'];
            try {
                $hana = new HanaQueryService();
                $lines = $hana->getSalesOrderLines($docEntry);
            } catch (\Throwable $e) {
                $sl = new SapServiceLayerClient();
                $sl->login();
                $doc = $sl->getSalesOrder($docEntry);
                $lines = $doc['DocumentLines'] ?? [];
                $sl->logout();
            }
            Response::success($lines);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * GET /api/sap/stock-transfers
     * Lista transferencias de stock desde SAP via Service Layer.
     */
    public static function stockTransfers(array $params): void
    {
        try {
            $sl = new SapServiceLayerClient();
            $sl->login();
            $r = $sl->getStockTransfers();
            $transfers = $r['value'] ?? $r;
            $sl->logout();
            Response::success($transfers);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * GET /api/sap/goods-receipts
     * Lista entradas de mercaderia (PurchaseDeliveryNotes) desde SAP via Service Layer.
     */
    public static function goodsReceipts(array $params): void
    {
        try {
            $sl = new SapServiceLayerClient();
            $sl->login();
            $r = $sl->getGoodsReceiptPO();
            $receipts = $r['value'] ?? $r;
            $sl->logout();
            Response::success($receipts);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * GET /api/sap/sync-log
     * Devuelve los ultimos registros del log de sync WMS<->SAP.
     */
    public static function syncLog(array $params): void
    {
        try {
            $limit = max(1, min((int)(Request::query('limit', 50)), 200));
            $type  = Request::query('type');
            $db = \WMS\Core\Database::getConnection();
            $where = ''; $args = [];
            if ($type) { $where = 'WHERE sync_type = ?'; $args[] = $type; }
            $sql = "SELECT id, sync_type, direction, sap_doc_type, sap_doc_entry,
                           sap_doc_num, wms_reference_id, status,
                           SUBSTRING(error_message,1,500) AS error_message,
                           retry_count, created_at
                    FROM sap_sync_log
                    {$where}
                    ORDER BY id DESC
                    LIMIT {$limit}";
            $st = $db->prepare($sql);
            $st->execute($args);
            Response::success($st->fetchAll(\PDO::FETCH_ASSOC));
        } catch (\Throwable $e) {
            Response::error('Error leyendo sync log: ' . $e->getMessage(), 500);
        }
    }

    /**
     * GET /api/sap/drivers
     * Lista choferes desde el UDO CENT_CHOFERES.
     */
    public static function drivers(array $params): void
    {
        try {
            $sl = new SapServiceLayerClient();
            $r  = $sl->get("/CENT_CHOFERES?\$select=Code,U_dNomChof,U_dNumIDChof,Canceled&\$top=200");
            $list = array_filter(($r['value'] ?? $r), fn($d) => ($d['Canceled'] ?? 'N') === 'N');
            $list = array_map(fn($d) => [
                'code'    => $d['Code'],
                'doc'     => $d['U_dNumIDChof'] ?? null,
                'name'    => $d['U_dNomChof'] ?? null,
            ], array_values($list));
            Response::success($list);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * GET /api/sap/vehicles
     * Lista vehiculos desde el UDO CENT_VEHICULOS.
     */
    public static function vehicles(array $params): void
    {
        try {
            $sl = new SapServiceLayerClient();
            $r  = $sl->get("/CENT_VEHICULOS?\$select=Code,U_dMarVeh,U_dNroMatVeh,U_dNomTrans,Canceled&\$top=200");
            $list = array_filter(($r['value'] ?? $r), fn($d) => ($d['Canceled'] ?? 'N') === 'N');
            $list = array_map(fn($d) => [
                'code'    => $d['Code'],
                'plate'   => $d['U_dNroMatVeh'] ?? null,
                'brand'   => $d['U_dMarVeh'] ?? null,
                'carrier' => $d['U_dNomTrans'] ?? null,
            ], array_values($list));
            Response::success($list);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * GET /api/sap/items
     * Lista artículos desde HANA.
     */
    public static function items(array $params): void
    {
        try {
            $top  = (int) (Request::query('top', 500));
            $skip = (int) (Request::query('skip', 0));
            try {
                $hana = new HanaQueryService();
                $items = $hana->getItems($top, $skip);
            } catch (\Throwable $e) {
                $sl = new SapServiceLayerClient();
                $sl->login();
                $r = $sl->getItems($top, $skip);
                $items = $r['value'] ?? $r;
                $sl->logout();
            }
            Response::success($items);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * POST /api/sap/sync-items
     * Importa artículos de SAP HANA a la tabla items de WMS (upsert por item_code).
     */
    public static function syncItems(array $params): void
    {
        try {
            // Try HANA first, fall back to Service Layer
            $sapItems = [];
            $source = 'unknown';
            try {
                $hana = new HanaQueryService();
                $sapItems = $hana->getItems(10000, 0);
                $source = 'HANA';
            } catch (\Throwable $e) {
                // HANA unavailable, use Service Layer (paginate to get all)
                $sl = new SapServiceLayerClient();
                $sl->login();
                $sapItems = [];
                $skip = 0;
                $pageSize = 20;
                do {
                    $response = $sl->getItems($pageSize, $skip);
                    $page = $response['value'] ?? $response;
                    if (!is_array($page) || empty($page)) break;
                    $sapItems = array_merge($sapItems, $page);
                    $skip += count($page);
                } while (count($page) >= $pageSize);
                $source = 'ServiceLayer';
                $sl->logout();
            }

            $db = Database::getConnection();
            $db->beginTransaction();

            $upsertSql = "INSERT INTO items (item_code, item_name, barcode, uom, requires_lot, requires_serial, item_group, sap_item_code)
                          VALUES (?, ?, ?, ?, ?, ?, ?, ?)
                          ON DUPLICATE KEY UPDATE
                              item_name = VALUES(item_name),
                              barcode = VALUES(barcode),
                              uom = VALUES(uom),
                              requires_lot = VALUES(requires_lot),
                              requires_serial = VALUES(requires_serial),
                              item_group = VALUES(item_group),
                              sap_item_code = VALUES(sap_item_code)";
            $stmt = $db->prepare($upsertSql);

            $synced = 0;
            foreach ($sapItems as $item) {
                // Map fields: HANA uses CodeBars/InvntryUom/ManBtchNum, SL uses BarCode/InventoryUOM/ManageBatchNumbers
                $code = $item['ItemCode'];
                $name = $item['ItemName'];
                $barcode = $item['CodeBars'] ?? $item['BarCode'] ?? null;
                $uom = $item['InvntryUom'] ?? $item['InventoryUOM'] ?? 'UN';
                $batch = $item['ManBtchNum'] ?? $item['ManageBatchNumbers'] ?? 'tNO';
                $serial = $item['ManSerNum'] ?? $item['ManageSerialNumbers'] ?? 'tNO';
                $group = $item['ItmsGrpNam'] ?? $item['ItemsGroupCode'] ?? null;

                $reqLot = ($batch === 'Y' || $batch === 'tYES') ? 1 : 0;
                $reqSerial = ($serial === 'Y' || $serial === 'tYES') ? 1 : 0;

                $stmt->execute([$code, $name, $barcode, $uom, $reqLot, $reqSerial, $group, $code]);
                $synced++;
            }

            $db->commit();

            Response::success([
                'message' => "Sincronizacion completada via {$source}",
                'synced'  => $synced,
            ]);
        } catch (\Throwable $e) {
            if (isset($db) && $db->inTransaction()) {
                $db->rollBack();
            }
            Response::error('Error al sincronizar articulos: ' . $e->getMessage(), 500);
        }
    }

    /**
     * POST /api/sap/sync-warehouses
     * Importa almacenes y bins de SAP HANA a WMS (upsert por code).
     */
    public static function syncWarehouses(array $params): void
    {
        try {
            // Try HANA first, fall back to Service Layer
            $sapWarehouses = [];
            $hanaAvailable = false;
            try {
                $hana = new HanaQueryService();
                $sapWarehouses = $hana->getWarehouses();
                $hanaAvailable = true;
            } catch (\Throwable $e) {
                $sl = new SapServiceLayerClient();
                $sl->login();
                $response = $sl->getWarehouses();
                $sapWarehouses = [];
                $raw = $response['value'] ?? $response;
                foreach ($raw as $w) {
                    $sapWarehouses[] = [
                        'WhsCode' => $w['WarehouseCode'] ?? $w['WhsCode'] ?? '',
                        'WhsName' => $w['WarehouseName'] ?? $w['WhsName'] ?? '',
                        'Street'  => $w['Street'] ?? null,
                    ];
                }
                $sl->logout();
            }

            $db = Database::getConnection();
            $db->beginTransaction();

            $upsertWhSql = "INSERT INTO warehouses (code, name, address, sap_warehouse_code)
                            VALUES (?, ?, ?, ?)
                            ON DUPLICATE KEY UPDATE
                                name = VALUES(name),
                                address = VALUES(address),
                                sap_warehouse_code = VALUES(sap_warehouse_code)";
            $whStmt = $db->prepare($upsertWhSql);

            $upsertBinSql = "INSERT INTO bins (warehouse_id, code, aisle, rack, level, position, sap_bin_code)
                             VALUES (?, ?, ?, ?, ?, ?, ?)
                             ON DUPLICATE KEY UPDATE
                                 aisle = VALUES(aisle),
                                 rack = VALUES(rack),
                                 level = VALUES(level),
                                 position = VALUES(position),
                                 sap_bin_code = VALUES(sap_bin_code)";
            $binStmt = $db->prepare($upsertBinSql);

            $whSynced  = 0;
            $binSynced = 0;

            foreach ($sapWarehouses as $wh) {
                $whStmt->execute([
                    $wh['WhsCode'],
                    $wh['WhsName'],
                    $wh['Street'] ?? null,
                    $wh['WhsCode'],
                ]);
                $whSynced++;

                // Obtener el ID del almacén (ya sea insertado o existente)
                $whIdStmt = $db->prepare("SELECT id FROM warehouses WHERE code = ?");
                $whIdStmt->execute([$wh['WhsCode']]);
                $whId = (int) $whIdStmt->fetchColumn();

                // Sincronizar bins del almacen (solo si HANA disponible)
                if (!$hanaAvailable) { continue; }
                $sapBins = $hana->getBinLocations($wh['WhsCode']);
                foreach ($sapBins as $bin) {
                    $binStmt->execute([
                        $whId,
                        $bin['BinCode'],
                        $bin['Aisle'] ?? null,
                        $bin['Rack'] ?? null,
                        $bin['Level'] ?? null,
                        $bin['Position'] ?? null,
                        $bin['BinCode'],
                    ]);
                    $binSynced++;
                }
            }

            $db->commit();

            Response::success([
                'message'          => 'Sincronización de almacenes completada',
                'warehouses_synced' => $whSynced,
                'bins_synced'       => $binSynced,
            ]);
        } catch (\Throwable $e) {
            if (isset($db) && $db->inTransaction()) {
                $db->rollBack();
            }
            Response::error('Error al sincronizar almacenes: ' . $e->getMessage(), 500);
        }
    }

    /**
     * GET /api/sap/connection-status
     * Prueba conectividad con SAP HANA y Service Layer.
     */
    public static function connectionStatus(array $params): void
    {
        $hanaStatus = ['connected' => false];
        $slStatus   = ['connected' => false];

        // Test HANA
        try {
            HanaDatabase::getConnection();
            $hanaStatus['connected'] = true;
        } catch (\Throwable $e) {
            $hanaStatus['error'] = $e->getMessage();
        }

        // Test Service Layer
        try {
            $sl = new SapServiceLayerClient();
            $sl->login();
            $slStatus['connected'] = true;
            $sl->logout();
        } catch (\Throwable $e) {
            $slStatus['error'] = $e->getMessage();
        }

        Response::success([
            'hana'          => $hanaStatus,
            'service_layer' => $slStatus,
        ]);
    }

    /**
     * GET /api/sap/credit-notes  (Notas de Credito ORIN)
     */
    public static function creditNotes(array $params): void
    {
        try {
            $sl = new SapServiceLayerClient();
            $sl->login();
            $r = $sl->getCreditNotes();
            $data = $r['value'] ?? $r;
            $sl->logout();
            Response::success($data);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

    /**
     * GET /api/sap/transfer-requests  (Solicitudes de Traslado OWTQ)
     */
    public static function transferRequests(array $params): void
    {
        try {
            $sl = new SapServiceLayerClient();
            $sl->login();
            $r = $sl->getTransferRequests();
            $data = $r['value'] ?? $r;
            $sl->logout();
            Response::success($data);
        } catch (\Throwable $e) {
            Response::error('SAP no disponible: ' . $e->getMessage(), 503);
        }
    }

}
