<?php

namespace WMS\Controllers;

use WMS\Core\Request;
use WMS\Core\Response;
use WMS\Core\Database;
use WMS\Helpers\Validator;
use WMS\Middleware\AuthMiddleware;
use WMS\Repositories\MenuRepository;

/**
 * MenuController - Lectura del menu dinamico segun rol del usuario,
 * y administracion de la matriz de permisos (admin only).
 */
class MenuController
{
    /** Vistas (pantallas) canónicas de la interfaz RF. Fuente de verdad para rf_role_access. */
    private const RF_VIEWS = [
        'recepcion'     => 'Recepción',
        'putaway'       => 'Putaway',
        'picking'       => 'Picking',
        'qa'            => 'Control QA',
        'conteo'        => 'Conteo',
        'ajuste'        => 'Ajuste',
        'transferencia' => 'Transferencia',
        'reubicacion'   => 'Reubicación',
        'consulta'      => 'Consulta de stock',
        'consulta-lpn'  => 'Consulta LPN',
    ];

    /**
     * GET /api/menu
     * Devuelve el menu visible para el rol del usuario autenticado.
     */
    public static function index(array $params): void
    {
        $user = AuthMiddleware::user();
        $role = strtolower((string)($user['role'] ?? 'op_almacen'));
        try {
            $repo = new MenuRepository();
            $menu = $repo->getMenuForRole($role);
            Response::success($menu, 'OK');
        } catch (\Throwable $e) {
            Response::error('Error al cargar menu: ' . $e->getMessage(), 500);
        }
    }

    /**
     * GET /api/rf-menu
     * Devuelve el mapa de acceso del menu de la interfaz RF para el rol actual.
     * Formato: { "recepcion":"F", "consulta":"R", ... } (F=FULL, R=READ).
     * Reemplaza el RF_ROLE_MATRIX hardcodeado de rf.html (tabla rf_role_access).
     */
    public static function rfMenu(array $params): void
    {
        $user = AuthMiddleware::user();
        $role = strtolower((string)($user['role'] ?? ''));
        try {
            $db = Database::getConnection();
            $stmt = $db->prepare("SELECT view_key, access_type FROM rf_role_access WHERE role = ?");
            $stmt->execute([$role]);
            $map = [];
            foreach ($stmt->fetchAll(\PDO::FETCH_ASSOC) as $r) {
                $map[$r['view_key']] = ($r['access_type'] === 'READ') ? 'R' : 'F';
            }
            Response::success($map, 'OK');
        } catch (\Throwable $e) {
            Response::error('Error al cargar menu RF: ' . $e->getMessage(), 500);
        }
    }

    /**
     * GET /api/rf-matrix
     * Matriz completa de permisos RF: vistas canónicas + filas actuales (rf_role_access).
     * Solo admin (la policy lo gates).
     */
    public static function rfMatrix(array $params): void
    {
        try {
            $db = Database::getConnection();
            $views = [];
            foreach (self::RF_VIEWS as $k => $name) {
                $views[] = ['view_key' => $k, 'name' => $name];
            }
            $rows = $db->query("SELECT view_key, role, access_type FROM rf_role_access")->fetchAll(\PDO::FETCH_ASSOC);
            Response::success(['views' => $views, 'rows' => $rows], 'OK');
        } catch (\Throwable $e) {
            Response::error('Error al cargar matriz RF: ' . $e->getMessage(), 500);
        }
    }

    /**
     * PUT /api/rf-access/{view_key}
     * Reemplaza los permisos de una pantalla RF.
     * Body: { perms: [{role:'op_almacen', access_type:'FULL'|'READ'}, ...] }
     */
    public static function setRfAccess(array $params): void
    {
        $vk = (string)($params['view_key'] ?? '');
        if (!array_key_exists($vk, self::RF_VIEWS)) {
            Response::error('Vista RF inválida: ' . $vk, 422);
            return;
        }
        $body = Request::body();
        $v = (new Validator($body))->required(['perms']);
        if (!$v->passes()) {
            Response::error('Datos invalidos', 422, $v->errors());
            return;
        }
        if (!is_array($body['perms'])) {
            Response::error('perms debe ser array', 422);
            return;
        }
        try {
            $db = Database::getConnection();
            $db->beginTransaction();
            $db->prepare("DELETE FROM rf_role_access WHERE view_key = ?")->execute([$vk]);
            $ins = $db->prepare("INSERT INTO rf_role_access (role, view_key, access_type) VALUES (?, ?, ?)");
            foreach ($body['perms'] as $p) {
                $role = strtolower(trim((string)($p['role'] ?? '')));
                $at   = (string)($p['access_type'] ?? '');
                if ($role !== '' && in_array($at, ['FULL', 'READ'], true)) {
                    $ins->execute([$role, $vk, $at]);
                }
            }
            $db->commit();
            Response::success(null, 'Permisos RF actualizados');
        } catch (\Throwable $e) {
            if (isset($db) && $db->inTransaction()) $db->rollBack();
            Response::error('Error al actualizar permisos RF: ' . $e->getMessage(), 500);
        }
    }

    /**
     * GET /api/menu/matrix
     * Matriz completa rol -> item -> access. Solo admin (la policy lo gates).
     */
    public static function matrix(array $params): void
    {
        try {
            $repo = new MenuRepository();
            Response::success($repo->fullMatrix(), 'OK');
        } catch (\Throwable $e) {
            Response::error('Error al cargar matriz: ' . $e->getMessage(), 500);
        }
    }

    /**
     * PUT /api/menu/items/{id}/access
     * Reemplaza permisos para un item dado.
     * Body: { perms: [{role:'op_almacen', access_type:'FULL'}, ...] }
     */
    public static function setItemAccess(array $params): void
    {
        $itemId = (int)($params['id'] ?? 0);
        if ($itemId <= 0) {
            Response::error('id invalido', 422);
            return;
        }
        $body = Request::body();
        $v = (new Validator($body))->required(['perms']);
        if (!$v->passes()) {
            Response::error('Datos invalidos', 422, $v->errors());
            return;
        }
        if (!is_array($body['perms'])) {
            Response::error('perms debe ser array', 422);
            return;
        }
        try {
            $repo = new MenuRepository();
            $repo->replaceItemAccess($itemId, $body['perms']);
            Response::success(null, 'Permisos actualizados');
        } catch (\Throwable $e) {
            Response::error('Error al actualizar: ' . $e->getMessage(), 500);
        }
    }
}
