<?php

declare(strict_types=1);

namespace PpPhp\Modules\Fields\Controllers;

use PpPhp\Core\Config;
use PpPhp\Core\ModuleManager;
use PpPhp\Core\DB;
use PpPhp\Core\Security;
use PpPhp\Core\ProjectNav;
use PpPhp\Core\ModuleState;

class FieldsController
{
    private array $project = [];
    private string $slug = '';

    public function __construct(
        private Config $config,
        private ModuleManager $moduleManager
    ) {}

    /**
     * Main SPA page.
     */
    public function index(string $slug): string
    {
        $this->initProject($slug);
        $project = $this->project;

        // Load Tables module state (selected tables)
        $tablesState = ModuleState::load($slug, 'tables');
        $selectedTableNames = $tablesState['selectedTables'] ?? [];

        // Load the plugin registry
        $pluginRegistry = \PpPhp\Core\PluginRegistry::all();

        // Build table list (fallback to all if nothing selected)
        $tables = [];
        if (empty($selectedTableNames)) {
            $rows = DB::Query('SHOW FULL TABLES')->fetchAll(\PDO::FETCH_NUM);
            foreach ($rows as $row) {
                $tables[] = [
                    'name' => $row[0],
                    'type' => ($row[1] === 'VIEW') ? 'VIEW' : 'TABLE',
                ];
            }
            usort($tables, fn($a, $b) => $a['name'] <=> $b['name']);
        } else {
            foreach ($selectedTableNames as $tableName) {
                $tables[] = ['name' => $tableName, 'type' => 'TABLE'];
            }
        }

        // Fields config now comes from its own file (config/fields.json)
        $fieldsState = ModuleState::load($slug, 'fields');
        $fieldsConfig = $fieldsState['byTable'] ?? [];
        $currentTableName = $fieldsState['activeTable'] ?? null;

        $navItems = ProjectNav::items('/fields');
        $baseUrl   = $this->config->get('base_url');
        $assetsUrl = $this->config->get('assets_url');
        $user      = $_SESSION['user'];
        $pageTitle = 'Fields';

        ob_start();
        include __DIR__ . '/../Views/index.php';
        return ob_get_clean();
    }

    // ── Private helpers ────────────────────────────────────────────────

    private function initProject(string $slug): void
    {
        Security::RequireAuth();
        $this->slug = $slug;

        DB::Init(); // central DB
        $project = DB::Select('projects', ['slug' => $slug, 'created_by' => Security::CurrentUserData()['id']]);
        if (empty($project) && Security::IsAdmin()) {
            $project = DB::Select('projects', ['slug' => $slug]);
        }
        if (empty($project)) {
            http_response_code(404);
            echo 'Project not found.';
            exit;
        }
        $this->project = $project[0];
        if (\PpPhp\Core\ProjectDatabaseProfile::isStandaloneSlug($slug)) {
            $_SESSION['project_flash'] = 'Fields isn’t available for standalone apps — this project has no database.';
            redirect('/project/' . rawurlencode($slug) . '/workspace');
        }
        DB::Init($slug);
        DB::SetConnection($slug);
    }


    /**
     * Save fields configuration for a table.
     */
    public function save(string $slug): void
    {
        header('Content-Type: application/json');
        $this->initProject($slug);
        \PpPhp\Core\Security::RequireCsrf(); // beacon carries the token via the keepalive-fetch shim

        $input = json_decode(file_get_contents('php://input'), true) ?? $_POST;
        $tableName = $input['tableName'] ?? '';
        $device = $input['device'] ?? 'desktop';
        $fields = $input['fields'] ?? [];

        if ($tableName === '') {
            http_response_code(400);
            echo json_encode(['success' => false, 'message' => 'Table name is required.']);
            exit;
        }

        $state = ModuleState::load($slug, 'fields');
        if (!isset($state['byTable'][$tableName])) {
            $state['byTable'][$tableName] = [
                'activeDevice' => $device,
                'devices' => [],
                'searchSettings' => (object) [],
            ];
        }
        $state['byTable'][$tableName]['activeDevice'] = $device;
        $state['byTable'][$tableName]['devices'][$device] = $fields;
        // Persist the per-field Search Settings the client sends (previously the
        // whole payload beyond `devices` was dropped, so the modal selections —
        // e.g. Show on Filter Panel — never saved). Force an OBJECT even when
        // empty so it never round-trips as a JS array (which silently loses
        // string keys on the client). View As / Edit As no longer live here.
        if (array_key_exists('searchSettings', $input)) {
            $ss = (array) ($input['searchSettings'] ?? []);
            $state['byTable'][$tableName]['searchSettings'] = $ss === [] ? (object) [] : $ss;
        }
        $state['activeTable'] = $tableName;
        ModuleState::save($slug, 'fields', $state);

        echo json_encode(['success' => true, 'message' => 'Fields configuration saved.']);
        exit;
    }

    /**
     * Load fields configuration for a table.
     */
    public function load(string $slug, string $table): void
    {
        header('Content-Type: application/json');
        $this->initProject($slug);

        $state = ModuleState::load($slug, 'fields');
        $config = $state['byTable'][$table] ?? [
            'activeDevice' => 'desktop',
            'devices' => (object) [],
            'searchSettings' => (object) [],
        ];
        // Normalise a legacy empty-array searchSettings to an object so the
        // client never receives `[]` (which would drop string keys on save).
        if (is_array($config) && (($config['searchSettings'] ?? null) === [] || !isset($config['searchSettings']))) {
            $config['searchSettings'] = (object) [];
        }

        echo json_encode(['success' => true, 'config' => $config]);
        exit;
    }
}
