<?php

namespace WMS\Controllers;

use WMS\Core\Request;
use WMS\Core\Response;
use WMS\Middleware\AuthMiddleware;
use WMS\Services\AgendaService;
use WMS\Repositories\AgendaRepository;
use WMS\Helpers\Validator;

/**
 * Controlador de Agenda de Recepcion.
 *
 * Endpoints:
 * - POST   /api/agendas                       -> create
 * - GET    /api/agendas                        -> index
 * - GET    /api/agendas/{id}                   -> show
 * - POST   /api/agendas/{id}/references        -> addReference
 * - DELETE /api/agendas/{id}/references/{ref_id} -> removeReference
 * - POST   /api/agendas/{id}/open              -> open
 * - POST   /api/agendas/{id}/scan              -> scan
 * - GET    /api/agendas/{id}/differences       -> getDifferences
 * - POST   /api/agendas/{id}/close             -> close
 */
class AgendaController
{
    /**
     * POST /api/agendas
     * Crea una nueva agenda de recepcion.
     * Body: { warehouse_id, planned_date, notes? }
     */
    public static function create(array $params): void
    {
        $body = Request::body();
        $v = (new Validator($body))
            ->required(['warehouse_id', 'planned_date'])
            ->date('planned_date');

        if (!$v->passes()) {
            Response::error('Datos invalidos', 422, $v->errors());
            return;
        }

        try {
            $service = new AgendaService();
            $result = $service->createAgenda($body, AuthMiddleware::userId());
            Response::success($result, 'Agenda creada', 201);
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * GET /api/agendas
     * Lista agendas filtradas por warehouse_id y opcionalmente por status.
     */
    public static function index(array $params): void
    {
        $warehouseId = Request::query('warehouse_id');
        if (!$warehouseId) {
            Response::error('El parametro warehouse_id es obligatorio', 422);
            return;
        }

        try {
            $repo = new AgendaRepository();
            $status = Request::query('status');
            $agendas = $repo->getByWarehouse((int) $warehouseId, $status);
            Response::success($agendas);
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * GET /api/agendas/{id}
     * Retorna una agenda con sus referencias, lineas, escaneos y diferencias.
     */
    public static function show(array $params): void
    {
        try {
            $repo = new AgendaRepository();
            $agenda = $repo->getWithDetails((int) $params['id']);
            if (!$agenda) {
                Response::error('Agenda no encontrada', 404);
                return;
            }
            Response::success($agenda);
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * POST /api/agendas/{id}/references
     * Asocia una OC de SAP a la agenda.
     * Body: { sap_doc_entry }
     */
    public static function addReference(array $params): void
    {
        $body = Request::body();
        if (empty($body['sap_doc_entry']) && empty($body['sap_doc_num'])) {
            Response::error('Ingrese el Nro. de OC (DocNum) o DocEntry', 400);
            return;
        }

        try {
            $service = new AgendaService();
            $result = $service->addReference(
                (int) $params['id'],
                $body,
                AuthMiddleware::userId()
            );
            Response::success($result, 'OC asociada a la agenda', 201);
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * DELETE /api/agendas/{id}/references/{ref_id}
     * Elimina una referencia (OC) de la agenda.
     */
    public static function removeReference(array $params): void
    {
        try {
            $service = new AgendaService();
            $result = $service->removeReference(
                (int) $params['id'],
                (int) $params['ref_id'],
                AuthMiddleware::userId()
            );
            Response::success($result, 'Referencia eliminada');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * POST /api/agendas/import-sap-po
     * Crea agenda + asocia OC SAP + auto-asigna al usuario si rol = op_recepcion.
     * Body: { sap_doc_entry?, sap_doc_num?, warehouse_id, planned_date?, notes? }
     */
    public static function importSapPo(array $params): void
    {
        $body = Request::body();
        try {
            $service = new AgendaService();
            $u = AuthMiddleware::user();
            $result = $service->importFromSapPurchaseOrder(
                $body,
                AuthMiddleware::userId(),
                $u['role'] ?? null
            );
            Response::success($result, 'Agenda creada desde OC SAP');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * POST /api/agendas/{id}/reconcile-stock
     * Genera stock para una agenda CERRADA cuyos escaneos no llegaron al WMS.
     */
    public static function reconcileStock(array $params): void
    {
        try {
            $service = new AgendaService();
            $result = $service->reconcileStock(
                (int) $params['id'],
                AuthMiddleware::userId()
            );
            Response::success($result, 'Stock reconciliado');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * POST /api/agenda-refs/{id}/retry-sap
     * Reintenta crear el PurchaseDeliveryNote en SAP para una ref en ERROR.
     */
    public static function retrySap(array $params): void
    {
        try {
            $service = new AgendaService();
            $result = $service->retrySapForRef(
                (int) $params['id'],
                AuthMiddleware::userId()
            );
            Response::success($result, 'Documento creado en SAP');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * POST /api/agendas/{id}/assign
     * Asigna la agenda a un operador. Body: { user_id, notes? }
     */
    public static function assign(array $params): void
    {
        $body = Request::body();
        if (empty($body['user_id'])) { Response::error('user_id requerido'); return; }

        try {
            $service = new AgendaService();
            $result = $service->assignAgenda(
                (int) $params['id'],
                (int) $body['user_id'],
                AuthMiddleware::userId(),
                $body['notes'] ?? null
            );
            Response::success($result, 'Agenda asignada');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * POST /api/agendas/{id}/open
     * Abre la agenda para recepcion fisica.
     */
    public static function open(array $params): void
    {
        try {
            $service = new AgendaService();
            $result = $service->openAgenda(
                (int) $params['id'],
                AuthMiddleware::userId()
            );
            Response::success($result, 'Agenda abierta para recepcion');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * POST /api/agendas/{id}/scan
     * Registra un escaneo ciego de producto.
     * Body: { item_code, quantity, batch_number?, expiry_date?, supplier_lot?, bin_id? }
     */
    public static function scan(array $params): void
    {
        $body = Request::body();
        $v = (new Validator($body))
            ->required(['item_code', 'quantity'])
            ->positiveNumber('quantity');

        if (!$v->passes()) {
            Response::error('Datos invalidos', 422, $v->errors());
            return;
        }

        try {
            $service = new AgendaService();
            $result = $service->scanItem(
                (int) $params['id'],
                $body,
                AuthMiddleware::userId()
            );
            Response::success($result, 'Escaneo registrado');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * GET /api/agendas/{id}/differences
     * Compara lo esperado vs lo recibido.
     */
    public static function getDifferences(array $params): void
    {
        try {
            $service = new AgendaService();
            $result = $service->getDifferences((int) $params['id']);
            Response::success($result);
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }

    /**
     * POST /api/agendas/{id}/close
     * Cierra la agenda y crea PurchaseDeliveryNotes en SAP.
     */
    public static function close(array $params): void
    {
        try {
            $service = new AgendaService();
            $result = $service->closeAgenda(
                (int) $params['id'],
                AuthMiddleware::userId()
            );
            Response::success($result, 'Agenda cerrada');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage());
        }
    }
}
