<?php

namespace Maestro\Core\Http\Controllers;

use Maestro\Core\DataTables\DataTableQueryApplier;
use Maestro\Core\DataTables\DataTableRegistry;
use Illuminate\Routing\Controller;
use Maestro\Core\Http\Requests\ExportDataTableRequest;
use Maestro\Core\Http\Requests\FetchDataTableRequest;
use Maestro\Core\Jobs\ExportDataTableJob;
use Maestro\Core\Models\DataTableExport;
use Illuminate\Http\JsonResponse;

use function activity;

/**
 * Generic DataTable endpoint: POST /api/datatables/{resourceKey}.
 * Export start: POST /api/datatables/{resourceKey}/export (async; returns export id + status).
 * B3: DataTableQueryApplier applies filters, global search, sort, pagination (or export without pagination).
 */
class DataTableController extends Controller
{
    public function __construct(
        private readonly DataTableRegistry $registry,
        private readonly DataTableQueryApplier $applier
    ) {}

    /**
     * Return column definitions for the frontend (key, header, type, searchable, filterable, defaultVisible).
     * Uses resource columns(); optional 'label' and 'defaultVisible' per column.
     */
    public function columns(\Illuminate\Http\Request $request, string $resourceKey): JsonResponse
    {
        $resource = $this->registry->resolve($resourceKey);
        $resource->authorize($request);

        $defs = $resource->columns();
        $out = [];
        foreach ($defs as $def) {
            $key = $def['key'] ?? null;
            if ($key === null) {
                continue;
            }
            $out[] = [
                'key' => $key,
                'header' => $def['label'] ?? $key,
                'type' => $def['type'] ?? 'text',
                'searchable' => (bool) ($def['searchable'] ?? false),
                'filterable' => (bool) ($def['filterable'] ?? false),
                'defaultVisible' => (bool) ($def['defaultVisible'] ?? true),
            ];
        }

        return response()->json($out);
    }

    /**
     * Fetch table data for the given resource key (B3: full query logic via applier).
     */
    public function fetch(FetchDataTableRequest $request, string $resourceKey): JsonResponse
    {
        $resource = $this->registry->resolve($resourceKey);
        $resource->authorize($request);

        $query = $resource->baseQuery($request);
        $columns = $resource->columns();
        $payload = $request->validated();

        // totalAll should reflect distinct primary ids, independent of any GROUP BY used for display.
        $countQuery = clone $query;
        $base = $countQuery->getQuery();
        $base->groups = null;
        $model = $countQuery->getModel();
        $idCol = $model ? $model->getTable() . '.id' : 'id';
        $totalAll = $countQuery->distinct($idCol)->count($idCol);

        $result = $this->applier->apply(
            $query,
            $columns,
            $payload,
            fn (object $model) => $resource->transformRow($model),
            $resource
        );

        $result['meta']['resourceKey'] = $resource->key();
        $result['meta']['totalAll'] = $totalAll;

        return response()->json($result);
    }

    /**
     * Start async CSV export. Authorized via resource view permission. Returns export id for polling.
     */
    public function export(ExportDataTableRequest $request, string $resourceKey): JsonResponse
    {
        $resource = $this->registry->resolve($resourceKey);
        $resource->authorize($request);

        $resourceLabel = trans('datatable.resources.' . $resourceKey);
        if ($resourceLabel === 'datatable.resources.' . $resourceKey) {
            $resourceLabel = $resourceKey;
        }

        $payload = $request->validated();
        $columns = $resource->columns();
        $exportColumns = $this->applier->orderedExportColumns($columns, $payload);
        if ($exportColumns === []) {
            return response()->json(['message' => 'No valid columns to export.'], 422);
        }

        $export = DataTableExport::create([
            'user_id' => $request->user()->id,
            'resource_key' => $resourceKey,
            'payload' => $payload,
            'status' => DataTableExport::STATUS_PENDING,
        ]);

        ExportDataTableJob::dispatch($export->id)->onQueue('exports');

        activity('data_export')
            ->causedBy($request->user())
            ->event('export')
            ->withProperties([
                'resource_key' => $resourceKey,
                'export_id' => $export->id,
                'status' => DataTableExport::STATUS_PENDING,
            ])
            ->log('Data export to CSV started for: ' . $resourceKey);

        return response()->json([
            'id' => $export->id,
            'status' => $export->status,
            'resourceKey' => $resourceKey,
            'resourceLabel' => $resourceLabel,
            'pollingIntervalHintMs' => 3000,
        ], 201);
    }
}
