<?php

namespace Maestro\Core\Http\Controllers;

use Maestro\Core\Http\Requests\UpdateTableStateRequest;
use Illuminate\Routing\Controller;
use Maestro\Core\Models\UserTableState;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;

/**
 * Per-user table state (column order, visible columns, filters, column widths) keyed by table_key.
 * GET returns state or null; PUT upserts by (user_id, table_key); DELETE removes record.
 */
class TableStateController extends Controller
{
    private const TABLE_KEY_MAX_LENGTH = 150;

    /**
     * Normalize state before save. Preserves filters as { key: { value: scalar|null|array<scalar|null> } }.
     * Filter values must be scalar|null or an array of scalars/nulls.
     * Max payload size is enforced in UpdateTableStateRequest.
     * Manual check: set a column filter, refresh page, confirm filter is restored.
     *
     * @return array{visibleColumns: list<string>, columnOrder: list<string>, globalSearch: string, filters: array<string, array{value: mixed}>, columnWidths: array<string, int>}
     */
    private static function normalizeState(array $state): array
    {
        $visibleColumns = $state['visibleColumns'] ?? [];
        $columnOrder = $state['columnOrder'] ?? [];
        $globalSearch = $state['globalSearch'] ?? '';
        $filters = $state['filters'] ?? [];
        $columnWidths = $state['columnWidths'] ?? [];

        $normalizedFilters = [];
        if (is_array($filters)) {
            foreach ($filters as $key => $entry) {
                if (! is_string($key)) {
                    continue;
                }


                $entry = is_array($entry) ? $entry : (is_object($entry) ? (array) $entry : null);
                if ($entry === null || ! array_key_exists('value', $entry)) {
                    continue;
                }


                $value = $entry['value'];
                if (is_object($value)) {
                    continue;
                }

                if (is_array($value)) {
                    $clean = [];
                    foreach ($value as $item) {
                        if (is_array($item) || is_object($item)) {
                            continue;
                        }
                        $clean[] = $item;
                    }
                    if ($clean === []) {
                        continue;
                    }
                    $filter = ['value' => array_values($clean)];
                } else {
                    $filter = ['value' => $value];
                }

                if (isset($entry['op']) && is_string($entry['op']) && $entry['op'] !== '') {
                    $filter['op'] = $entry['op'];
                }

                $normalizedFilters[$key] = $filter;
            }
        }

        $normalizedColumnWidths = [];
        if (is_array($columnWidths)) {
            foreach ($columnWidths as $key => $value) {
                if (! is_string($key) || $key === '') {
                    continue;
                }
                if (! is_numeric($value)) {
                    continue;
                }
                $w = (int) round((float) $value);
                if ($w < 48 || $w > 800) {
                    continue;
                }
                $normalizedColumnWidths[$key] = $w;
            }
        }

        return [
            'visibleColumns' => is_array($visibleColumns) ? array_values(array_filter($visibleColumns, 'is_string')) : [],
            'columnOrder' => is_array($columnOrder) ? array_values(array_filter($columnOrder, 'is_string')) : [],
            'globalSearch' => is_string($globalSearch) ? $globalSearch : '',
            'filters' => $normalizedFilters,
            'columnWidths' => $normalizedColumnWidths,
        ];
    }

    /**
     * Validate table_key from route (max length, non-empty).
     */
    private function validateTableKey(string $tableKey): JsonResponse|true
    {
        $validator = Validator::make(
            ['table_key' => $tableKey],
            ['table_key' => ['required', 'string', 'max:' . self::TABLE_KEY_MAX_LENGTH]]
        );

        if ($validator->fails()) {
            return response()->json([
                'message' => 'Validation failed',
                'errors' => $validator->errors(),
            ], 422);
        }

        return true;
    }

    /**
     * GET /api/table-states/{tableKey}
     * Returns { tableKey, state } with state null when no record exists.
     */
    public function show(string $tableKey): JsonResponse
    {
        $valid = $this->validateTableKey($tableKey);
        if ($valid !== true) {
            return $valid;
        }

        $record = UserTableState::query()
            ->where('user_id', Auth::id())
            ->where('table_key', $tableKey)
            ->first();

        return response()->json([
            'tableKey' => $tableKey,
            'state' => $record?->state,
        ]);
    }

    /**
     * PUT /api/table-states/{tableKey}
     * Body: { state: {...} }. Upserts by (user_id, table_key). Never writes for another user.
     * State is normalized; payload max 50KB (422 if exceeded).
     */
    public function update(UpdateTableStateRequest $request, string $tableKey): JsonResponse
    {
        $valid = $this->validateTableKey($tableKey);
        if ($valid !== true) {
            return $valid;
        }

        $userId = $request->user()->id;
        $state = self::normalizeState($request->input('state'));
        $payloadBytes = strlen(json_encode($state));

        $record = UserTableState::query()->updateOrCreate(
            [
                'user_id' => $userId,
                'table_key' => $tableKey,
            ],
            [
                'state' => $state,
            ]
        );

        Log::info('Table state updated', [
            'user_id' => $userId,
            'table_key' => $tableKey,
            'size_bytes' => $payloadBytes,
        ]);

        return response()->json([
            'tableKey' => $record->table_key,
            'state' => $record->state,
        ]);
    }

    /**
     * DELETE /api/table-states/{tableKey}
     * Removes the record for the authenticated user. Returns 204 No Content.
     */
    public function destroy(string $tableKey): JsonResponse
    {
        $valid = $this->validateTableKey($tableKey);
        if ($valid !== true) {
            return $valid;
        }

        UserTableState::query()
            ->where('user_id', Auth::id())
            ->where('table_key', $tableKey)
            ->delete();

        return response()->json(null, 204);
    }
}
