<?php

namespace App\Http\Controllers;

use Inertia\Inertia;
use App\Models\Project;
use App\Models\Collection;
use App\Models\ContentEntry;
use Illuminate\Http\Request;
use App\Models\ContentFieldValue;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use App\Http\Requests\ContentRequest;
use App\Http\Controllers\Controller;
use App\Models\Field;
use App\Models\FieldValue;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\DB;

class ContentController extends Controller
{
    public function create(Project $project, Collection $collection)
    {
        // If collection is singleton and already has an entry, redirect to edit page of that entry
        if ($collection->is_singleton) {
            $existingEntry = $collection->contentEntries()->latest('updated_at')->first();
            if ($existingEntry) {
                return redirect()->route('projects.collections.content.edit', [
                    'project' => $project->id,
                    'collection' => $collection->id,
                    'contentEntry' => $existingEntry->id,
                ]);
            }
        }

        return Inertia::render('Collections/Show', [
            'project' => $project->load('collections'),
            'collection' => $collection->load('fields')
        ]);
    }

    public function store(Project $project, Collection $collection, ContentRequest $request)
    {
        // Get status from request
        $status = $request->input('status', 'draft');
        
        // Validate status
        if (!in_array($status, ['draft', 'published'])) {
            $status = 'draft';
        }
        
        // Create content entry
        $contentEntry = new ContentEntry([
            'project_id' => $project->id,
            'collection_id' => $collection->id,
            'locale' => $request->input('locale', $project->default_locale),
            'status' => $status,
            'created_by' => Auth::id(),
            'updated_by' => Auth::id(),
        ]);
        
        // Set published_at if status is published
        if ($status === 'published') {
            $contentEntry->published_at = now();
        }
        
        $contentEntry->save();

        // Save field values
        $fieldData = $request->input('data', []);
        foreach ($fieldData as $fieldName => $value) {
            $field = $collection->fields()->where('name', $fieldName)->first();
            
            if (!$field) {
                continue;
            }
            
            // Handle repeatable fields
            if (isset($field->options['repeatable']) && $field->options['repeatable'] && is_array($value)) {
                foreach ($value as $item) {
                    $this->saveFieldValue($contentEntry, $field, $item['value'] ?? null);
                }
            } else {
                $this->saveFieldValue($contentEntry, $field, $value);
            }
        }
        
        // reload with relations and dispatch event
        $contentEntry->load(['fieldValues.field','fieldValues.mediaRelations.asset.metadata','fieldValues.valueRelations.related']);

        event(new \App\Events\ContentEvent('content.created', $project, $contentEntry));

        // Return simple JSON response matching UserManagement pattern
        return response()->json([
            'message' => 'Content ' . ($status === 'published' ? 'published' : 'saved') . ' successfully',
            'entry_id' => $contentEntry->id
        ]);
    }
    
    public function edit(Project $project, Collection $collection, ContentEntry $contentEntry)
    {
        // Make sure the content entry belongs to this project and collection
        if ($contentEntry->project_id !== $project->id || $contentEntry->collection_id !== $collection->id) {
            abort(404);
        }

        $collection = $collection->load('fields');
        
        // Load field values with media relations and assets
        $contentEntry->load([
            'fieldValues.mediaRelations.asset.metadata',
            'creator',
            'updater'
        ]);
        
        // Format field values into a usable structure for the frontend
        $formattedData = [];
        foreach ($contentEntry->fieldValues as $fieldValue) {
            $field = $collection->fields->first(function ($field) use ($fieldValue) {
                return $field->id === $fieldValue->field_id;
            });
            
            if (!$field) {
                continue;
            }
            
            $value = null;
            
            // Get the value based on field type
            switch ($fieldValue->field_type) {
                case 'number':
                    $value = $fieldValue->number_value;
                    break;
                case 'boolean':
                    $value = $fieldValue->boolean_value;
                    break;
                case 'date':
                    if (isset($field->options['mode']) && $field->options['mode'] === 'range') {
                        if (isset($field->options['includeTime']) && $field->options['includeTime']) {
                            $value = $fieldValue->datetime_value . ' - ' . $fieldValue->datetime_value_end;
                        } else {
                            $value = $fieldValue->date_value . ' - ' . $fieldValue->date_value_end;
                        }
                    } else {
                        if (isset($field->options['includeTime']) && $field->options['includeTime']) {
                            $value = $fieldValue->datetime_value;
                        } else {
                            $value = $fieldValue->date_value;
                        }
                    }
                    break;
                case 'time':
                    $value = $fieldValue->text_value;
                    break;
                case 'enumeration':
                    // For enumeration fields, make sure we have an array
                    $value = $fieldValue->json_value;
                    if (is_null($value)) {
                        $value = $field->options['multiple'] ? [] : null;
                    }
                    // Convert string values to arrays if needed
                    if (is_string($value) && !empty($value)) {
                        try {
                            $value = json_decode($value, true);
                        } catch (\Exception $e) {
                            // If we can't decode it as JSON, treat as a single value
                            $value = [$value];
                        }
                    }
                    break;
                case 'json':
                    $value = $fieldValue->json_value;
                    break;
                case 'media':
                    // Get full asset data for each media relation
                    $assets = $fieldValue->mediaRelations->map(function ($relation) {
                        $asset = $relation->asset;
                        if ($asset) {
                            $asset->full_url = Storage::disk($asset->disk)->url($asset->path);
                            $asset->thumbnail_url = $asset->thumbnail_url;
                            $asset->formatted_size = $asset->getFormattedSize();
                        }
                        return $asset;
                    })->filter()->values()->toArray();
                    
                    $value = $assets;
                    break;
                case 'relation':
                    $value = $fieldValue->valueRelations->pluck('related_id')->toArray();
                    break;
                default:
                    $value = $fieldValue->text_value;
            }
            
            // Handle repeatable fields
            if (isset($field->options['repeatable']) && $field->options['repeatable']) {
                if (!isset($formattedData[$field->name])) {
                    $formattedData[$field->name] = [];
                }
                $formattedData[$field->name][] = ['value' => $value];
            } else {
                $formattedData[$field->name] = $value;
            }
        }
        
        return Inertia::render('Collections/Show', [
            'project' => $project->load('collections'),
            'collection' => $collection,
            'contentEntry' => $contentEntry,
            'formData' => $formattedData,
            'isEditMode' => true
        ]);
    }
    
    public function update(ContentRequest $request, Project $project, Collection $collection, ContentEntry $contentEntry)
    {
        // Make sure the content entry belongs to this project and collection
        if ($contentEntry->project_id !== $project->id || $contentEntry->collection_id !== $collection->id) {
            abort(404);
        }
        
        // Get status from request
        $originalStatus = $contentEntry->status;
        $status = $request->input('status', $originalStatus);
        
        // Validate status
        if (!in_array($status, ['draft', 'published'])) {
            $status = $contentEntry->status;
        }
        
        // Update content entry
        $contentEntry->status = $status;
        $contentEntry->locale = $request->input('locale', $project->default_locale);
        $contentEntry->updated_by = Auth::id();
        $contentEntry->updated_at = now();
        
        // Set published_at if status changed to published
        if ($status === 'published' && $contentEntry->published_at === null) {
            $contentEntry->published_at = now();
        }
        
        $contentEntry->save();

        // CHECK! Get existing password values before deleting
        $passwordFields = $collection->fields()->where('type', 'password')->pluck('id');
        $existingPasswords = $contentEntry->fieldValues()
            ->whereIn('field_id', $passwordFields)
            ->get()
            ->keyBy('field_id');
        
        // Remove existing field values
        $contentEntry->fieldValues()->forceDelete();
        
        // Save field values
        $fieldData = $request->input('data', []);
        foreach ($fieldData as $fieldName => $value) {
            $field = $collection->fields()->where('name', $fieldName)->first();
            
            if (!$field) {
                continue;
            }
            
            // Handle repeatable fields
            if (isset($field->options['repeatable']) && $field->options['repeatable'] && is_array($value)) {
                foreach ($value as $item) {
                    $this->saveFieldValue($contentEntry, $field, $item['value'] ?? null);
                }
            } else {
                // For password fields, if value is empty, use existing value
                if ($field->type === 'password' && empty($value) && isset($existingPasswords[$field->id])) {
                    $this->saveFieldValue($contentEntry, $field, $existingPasswords[$field->id]->text_value);
                } else {
                    $this->saveFieldValue($contentEntry, $field, $value);
                }
            }
        }

        // reload with relations and dispatch event
        $contentEntry->load(['fieldValues.field','fieldValues.mediaRelations.asset.metadata','fieldValues.valueRelations.related']);

        // Dispatch additional events based on status change
        if($originalStatus !== $status){
            if($status === 'published'){
                event(new \App\Events\ContentEvent('content.published', $project, $contentEntry));
            }elseif($originalStatus === 'published' && $status !== 'published'){
                event(new \App\Events\ContentEvent('content.unpublished', $project, $contentEntry));
            }
        } else {
            event(new \App\Events\ContentEvent('content.updated', $project, $contentEntry));
        }
        
        return response()->json([
            'message' => 'Content ' . ($status === 'published' ? 'published' : 'saved') . ' successfully',
            'entry_id' => $contentEntry->id
        ]);
    }
    
    protected function saveFieldValue($contentEntry, $field, $value)
    {
        // Skip if value is empty and field is not required
        if (
            (is_null($value) || $value === '') && 
            (!isset($field->validations['required']) || !$field->validations['required']['status'])
        ) {
            return;
        }

        $fieldValue = new ContentFieldValue([
            'project_id' => $contentEntry->project_id,
            'collection_id' => $contentEntry->collection_id,
            'content_entry_id' => $contentEntry->id,
            'field_id' => $field->id,
            'field_type' => $field->type,
        ]);
        
        // Set the appropriate value column based on field type
        switch ($field->type) {
            case 'text':
                $fieldValue->text_value = $value;
                break;
            case 'longtext':
                $fieldValue->text_value = $value;
                break;
            case 'richtext':
                $fieldValue->text_value = $value;
                break;
            case 'slug':
                $fieldValue->text_value = $value;
                break;
            case 'email':
                $fieldValue->text_value = $value;
                break;
            case 'password':
                if ($value) {
                    $fieldValue->text_value = Hash::make($value);
                }
                break;
            case 'number':
                $fieldValue->number_value = $value;
                break;
            case 'enumeration':
                $fieldValue->json_value = is_array($value) ? $value : [$value];
                break;
            case 'boolean':
                $fieldValue->boolean_value = (bool) $value;
                break;
            case 'color':
                $fieldValue->text_value = $value;
                break;
            case 'date':
                if (isset($field->options['mode']) && $field->options['mode'] === 'range') {
                    
                    // Handle date range
                    if (is_string($value)) {
                        $dates = explode(' - ', $value);
                        
                        if (isset($field->options['includeTime']) && $field->options['includeTime']) {
                            $fieldValue->datetime_value = $dates[0];
                            $fieldValue->datetime_value_end = $dates[1];
                        } else {
                            $fieldValue->date_value = $dates[0];
                            $fieldValue->date_value_end = $dates[1];
                        }
                    }
                } else {
                    // Handle single date
                    if (isset($field->options['includeTime']) && $field->options['includeTime']) {
                        $fieldValue->datetime_value = $value;
                    } else {
                        $fieldValue->date_value = $value;
                    }
                }
                break;
            case 'time':
                $fieldValue->text_value = $value;
                break;
            case 'media':
                // Ensure value is an array
                $mediaIds = is_array($value) ? $value : [$value];
                // Filter out any null or empty values
                $mediaIds = array_filter($mediaIds, function($id) {
                    return !empty($id) && is_numeric($id);
                });
                // Store the IDs in json_value
                $fieldValue->json_value = $mediaIds;
                $fieldValue->save();
                $this->handleMediaRelations($fieldValue, $mediaIds);
                return;
            case 'relation':
                $fieldValue->json_value = is_array($value) ? $value : [$value];
                $fieldValue->save();
                $this->handleRelationFields($fieldValue, $value);
                return;
            case 'json':
                $fieldValue->json_value = is_array($value) ? $value : json_decode($value, true);
                break;
            default:
                $fieldValue->text_value = (string) $value;
                break;
        }

        $fieldValue->save();
    }
    
    protected function handleMediaRelations($fieldValue, $mediaIds)
    {
        // If mediaIds is empty, just return
        if (empty($mediaIds)) {
            return;
        }
        
        // Ensure mediaIds is always an array
        if (!is_array($mediaIds)) {
            $mediaIds = [$mediaIds];
        }
        
        // Filter out any null or empty values and ensure they are numeric
        $mediaIds = array_filter($mediaIds, function($id) {
            return !empty($id) && is_numeric($id);
        });
        
        // If no valid IDs remain, just return
        if (empty($mediaIds)) {
            return;
        }
        
        // Delete existing relations
        $fieldValue->mediaRelations()->delete();
        
        // Create new relations
        foreach ($mediaIds as $mediaId) {
            $fieldValue->mediaRelations()->create([
                'asset_id' => $mediaId,
            ]);
        }
    }

    public function getRelationCollection(Project $project, Collection $collection)
    {
        return $collection->load('fields');
    }
    
    protected function handleRelationFields($fieldValue, $relationIds)
    {
        if (empty($relationIds)) {
            return;
        }
        
        if (!is_array($relationIds)) {
            $relationIds = [$relationIds];
        }
        
        foreach ($relationIds as $relationId) {
            if (empty($relationId)) continue;
            
            $fieldValue->valueRelations()->create([
                'related_id' => $relationId,
                'related_type' => \App\Models\ContentEntry::class,
            ]);
        }
    }
    
    /**
     * Soft delete a content entry.
     */
    public function destroy(Project $project, Collection $collection, ContentEntry $contentEntry)
    {
        // Make sure the content entry belongs to this project and collection
        if ($contentEntry->project_id !== $project->id || $contentEntry->collection_id !== $collection->id) {
            abort(404);
        }

        event(new \App\Events\ContentEvent('content.trashed', $project, $contentEntry));
        
        $contentEntry->delete();
        
        return response()->json([
            'message' => 'Content moved to trash successfully',
        ]);
    }
    
    /**
     * Permanently delete a content entry.
     */
    public function forceDestroy(Project $project, Collection $collection, ContentEntry $contentEntry)
    {
        // Make sure the content entry belongs to this project and collection
        if ($contentEntry->project_id !== $project->id || $contentEntry->collection_id !== $collection->id) {
            abort(404);
        }

        event(new \App\Events\ContentEvent('content.deleted', $project, $contentEntry));
        
        // Delete related field values first
        $contentEntry->fieldValues()->forceDelete();
        
        // Force delete the content entry
        $contentEntry->forceDelete();
        
        return response()->json([
            'message' => 'Content permanently deleted successfully',
        ]);
    }

    /**
     * Search content entries for data table.
     */
    public function search(Request $request, Project $project, Collection $collection)
    {
        $collection = $collection->load('fields');

        $query = ContentEntry::with(['creator:id,name', 'updater:id,name'])
            ->where('content_entries.project_id', $project->id)
            ->where('content_entries.collection_id', $collection->id);

        // Handle trashed filter
        if ($request->input('filter_status') === 'trashed') {
            $query->onlyTrashed();
        } else {
            $query->whereNull('content_entries.deleted_at');
        }
        
        // Handle search
        if ($request->has('search') && $request->search) {
            $searchTerm = $request->search;
            
            // Find searchable field values (contains the search term)
            $contentEntryIds = ContentFieldValue::where('project_id', $project->id)
                ->where('collection_id', $collection->id)
                ->where(function ($q) use ($searchTerm) {
                    $q->where('text_value', 'like', "%{$searchTerm}%")
                      ->orWhere('number_value', 'like', "%{$searchTerm}%");
                })
                ->pluck('content_entry_id')
                ->unique();
            
            // Also include IDs and UUIDs
            $query->where(function($q) use ($searchTerm, $contentEntryIds) {
                $q->where('content_entries.id', 'like', "%{$searchTerm}%")
                  ->orWhere('content_entries.uuid', 'like', "%{$searchTerm}%")
                  ->orWhereIn('content_entries.id', $contentEntryIds);
            });
        }
        
        // Handle sorting
        if ($request->has('sort') && $request->sort && $request->input('filter_status') !== 'trashed') {
            $direction = $request->has('direction') && in_array($request->direction, ['asc', 'desc']) 
                ? $request->direction 
                : 'asc';
            
            // Special case for field values
            $sortColumn = $request->sort;
            
            // Standard columns we can sort on directly
            $standardColumns = ['id', 'uuid', 'status', 'created_at', 'updated_at', 'published_at', 'locale'];
            
            if (in_array($sortColumn, $standardColumns)) {
                $query->orderBy($sortColumn, $direction);
            } else {
                /**
                 * Attempt to sort using dynamic field value.
                 * We join the content_field_values table once for the requested field
                 * and order by the appropriate value column depending on field type.
                 */
                $sortField = $collection->fields->firstWhere('name', $sortColumn);

                if ($sortField) {
                    $alias = 'sort_value';

                    // Ensure we only join once
                    $query->leftJoin("content_field_values as {$alias}", function ($join) use ($alias, $sortField) {
                        $join->on("{$alias}.content_entry_id", '=', 'content_entries.id')
                             ->where("{$alias}.field_id", '=', $sortField->id);
                    });

                    // Select base columns to avoid ambiguous field list
                    $query->select('content_entries.*');

                    // Determine which column to sort on based on field type
                    switch ($sortField->type) {
                        case 'number':
                            $valueColumn = "{$alias}.number_value";
                            break;
                        case 'boolean':
                            $valueColumn = "{$alias}.boolean_value";
                            break;
                        case 'date':
                        case 'datetime':
                            $valueColumn = "{$alias}.date_value";
                            break;
                        default:
                            $valueColumn = "{$alias}.text_value";
                    }

                    // MySQL doesn't support NULLS LAST; emulate by sorting nulls after non-null values
                    // First sort by whether the value is NULL, then by the actual value
                    $query->orderByRaw("ISNULL({$valueColumn}) ASC");
                    $query->orderByRaw("{$valueColumn} {$direction}");
                } else {
                    // Fallback to default order if field not found
                    $query->orderBy('updated_at', 'desc');
                }
            }
        } else {
            // Default sort
            $query->orderBy('updated_at', 'desc');
        }
        
        // Handle filters
        foreach ($request->all() as $key => $value) {
            if (strpos($key, 'filter_') === 0 && $value) {
                $field = str_replace('filter_', '', $key);
                
                if (in_array($field, ['status', 'locale'])) {
                    if($field === 'status' && $value === 'trashed') {
                        continue; // skip applying status filter for trashed view
                    }
                    $query->where($field, $value);
                }
            }
        }
        
        // Handle date range filters for created_at, updated_at, published_at
        foreach (['created_at', 'updated_at', 'published_at'] as $dateField) {
            if ($request->has("{$dateField}_from") && $request->input("{$dateField}_from")) {
                $query->whereDate($dateField, '>=', $request->input("{$dateField}_from"));
            }
            
            if ($request->has("{$dateField}_to") && $request->input("{$dateField}_to")) {
                $query->whereDate($dateField, '<=', $request->input("{$dateField}_to"));
            }
        }
        
        // Get content entries with pagination
        $perPage = $request->input('per_page', 10);
        $contentEntries = $query->paginate($perPage);
        
        // Fetch field values for the content entries
        $entryIds = $contentEntries->pluck('id')->toArray();
        $fieldValues = ContentFieldValue::where('project_id', $project->id)
            ->where('collection_id', $collection->id)
            ->whereIn('content_entry_id', $entryIds)
            ->with(['mediaRelations.asset.metadata', 'valueRelations'])
            ->get();
        
        // Group field values by content entry
        $fieldValuesByEntry = [];
        foreach ($fieldValues as $fieldValue) {
            $entryId = $fieldValue->content_entry_id;
            $fieldId = $fieldValue->field_id;
            
            if (!isset($fieldValuesByEntry[$entryId])) {
                $fieldValuesByEntry[$entryId] = [];
            }
            
            //without additional query
            $field = $collection->fields->first(function ($field) use ($fieldId) {
                return $field->id === $fieldId;
            });
            
            if (!$field) {
                continue;
            }
            
            $value = null;
            
            // Get the value based on field type
            switch ($fieldValue->field_type) {
                case 'number':
                    $value = $fieldValue->number_value;
                    break;
                case 'boolean':
                    $value = $fieldValue->boolean_value;
                    break;
                case 'date':
                    // Check if the field has includeTime option
                    if ($field && isset($field->options['mode']) && $field->options['mode'] === 'range') {
                        if ($field && isset($field->options['includeTime']) && $field->options['includeTime']) {
                            $value = $fieldValue->datetime_value . ' - ' . $fieldValue->datetime_value_end;
                        } else {
                            $value = $fieldValue->date_value . ' - ' . $fieldValue->date_value_end;
                        }
                    } else {
                        if ($field && isset($field->options['includeTime']) && $field->options['includeTime']) {
                            $value = $fieldValue->datetime_value;
                        } else {
                            $value = $fieldValue->date_value;
                        }
                    }
                    break;
                case 'time':
                    $value = $fieldValue->text_value;
                    break;
                case 'enumeration':
                    // For enumeration fields, make sure we have an array
                    $value = $fieldValue->json_value;
                    if (is_null($value)) {
                        $value = $field->options['multiple'] ? [] : null;
                    }
                    // Convert string values to arrays if needed
                    if (is_string($value) && !empty($value)) {
                        try {
                            $value = json_decode($value, true);
                        } catch (\Exception $e) {
                            // If we can't decode it as JSON, treat as a single value
                            $value = [$value];
                        }
                    }
                    break;
                case 'json':
                    $value = $fieldValue->json_value;
                    break;
                case 'enum':
                    $value = $fieldValue->json_value;
                    break;
                case 'media':
                    // Get full asset data for each media relation
                    $assets = $fieldValue->mediaRelations->map(function ($relation) use ($project) {
                        $asset = $relation->asset;
                        if ($asset) {
                            $asset->full_url = Storage::disk($asset->disk)->url($asset->path);
                            $asset->thumbnail_url = $asset->thumbnail_url;
                            $asset->formatted_size = $asset->getFormattedSize();
                        }
                        return $asset;
                    })->filter()->values()->toArray();
                    
                    $value = $assets;
                    break;
                case 'relation':
                    $value = $fieldValue->valueRelations->pluck('related_id')->toArray();
                    break;
                default:
                    $value = $fieldValue->text_value;
            }
            
            // Handle repeatable fields: accumulate values instead of overwriting
            $isRepeatable = isset($field->options['repeatable']) && $field->options['repeatable'];

            if ($isRepeatable) {
                if (!isset($fieldValuesByEntry[$entryId][$field->name])) {
                    $fieldValuesByEntry[$entryId][$field->name] = [];
                }
                $fieldValuesByEntry[$entryId][$field->name][] = $value;
            } else {
                $fieldValuesByEntry[$entryId][$field->name] = $value;
            }
        }
        
        // Add field values to content entries
        $contentEntries->getCollection()->transform(function ($entry) use ($fieldValuesByEntry) {
            $entryId = $entry->id;
            
            if (isset($fieldValuesByEntry[$entryId])) {
                foreach ($fieldValuesByEntry[$entryId] as $fieldName => $value) {
                    $entry->{$fieldName} = $value;
                }
            }
            
            return $entry;
        });
        
        return $contentEntries;
    }

    /**
     * Return specific content entries (by IDs) together with their dynamic field values.
     * This is mainly used by the relation field in edit mode to render already-selected
     * entries without another complex query on the front-end.
     */
    public function find(Request $request, Project $project, Collection $collection)
    {
        $ids = $request->input('ids');
        if (empty($ids)) {
            return [];
        }

        if (!is_array($ids)) {
            $ids = explode(',', (string) $ids);
        }

        $entriesQuery = ContentEntry::where('project_id', $project->id)
            ->where('collection_id', $collection->id)
            ->whereIn('id', $ids)
            ->with(['creator', 'updater']);

        $entries = $entriesQuery->get();

        // Attach dynamic field values (re-use logic from search)
        if ($entries->isEmpty()) {
            return $entries;
        }

        // Fetch field values for these entries
        $fieldValues = ContentFieldValue::where('project_id', $project->id)
            ->where('collection_id', $collection->id)
            ->whereIn('content_entry_id', $ids)
            ->with(['mediaRelations', 'valueRelations'])
            ->get();

        $fields = $collection->fields;

        $fieldValuesByEntry = [];
        foreach ($fieldValues as $fieldValue) {
            $field = $fields->first(fn($f) => $f->id === $fieldValue->field_id);
            if (!$field) continue;

            $value = null;
            switch ($fieldValue->field_type) {
                case 'number':
                    $value = $fieldValue->number_value;
                    break;
                case 'enumeration':
                case 'json':
                    $value = $fieldValue->json_value;
                    break;
                case 'boolean':
                    $value = $fieldValue->boolean_value;
                    break;
                case 'date':
                case 'time':
                case 'datetime':
                    $value = $fieldValue->datetime_value ?? $fieldValue->date_value;
                    break;
                case 'media':
                    $value = $fieldValue->mediaRelations->pluck('asset_id')->toArray();
                    break;
                case 'relation':
                    $value = $fieldValue->valueRelations->pluck('related_id')->toArray();
                    break;
                default:
                    $value = $fieldValue->text_value;
            }

            $fieldValuesByEntry[$fieldValue->content_entry_id][$field->name] = $value;
        }

        $entries->transform(function ($entry) use ($fieldValuesByEntry) {
            if (isset($fieldValuesByEntry[$entry->id])) {
                foreach ($fieldValuesByEntry[$entry->id] as $key => $val) {
                    $entry->{$key} = $val;
                }
            }
            return $entry;
        });

        return $entries;
    }

    /** Restore soft deleted entry */
    public function restore(Project $project, Collection $collection, $contentEntry)
    {
        $entry = ContentEntry::withTrashed()->where([
            'id' => $contentEntry,
            'project_id' => $project->id,
            'collection_id' => $collection->id,
        ])->firstOrFail();

        $entry->restore();

        $entry->load(['fieldValues.field','fieldValues.mediaRelations.asset.metadata','fieldValues.valueRelations.related']);

        event(new \App\Events\ContentEvent('content.restored', $project, $entry));

        return response()->json(['message' => 'Content restored']);
    }

    public function duplicate(Project $project, Collection $collection, ContentEntry $contentEntry)
    {
        // Ensure entry belongs to project/collection
        if ($contentEntry->project_id !== $project->id || $contentEntry->collection_id !== $collection->id) {
            abort(404);
        }

        $newEntry = DB::transaction(function() use ($contentEntry, $project) {
            $newEntry = $contentEntry->replicate(['uuid','published_at','created_at','updated_at']);
            $newEntry->status = 'draft';
            $newEntry->created_by = auth()->id();
            $newEntry->updated_by = auth()->id();
            $newEntry->push();

            // clone field values
            $contentEntry->fieldValues()->with(['mediaRelations','valueRelations'])->get()->each(function($fv) use ($newEntry) {
                $newValue = $fv->replicate(['content_entry_id','created_at','updated_at']);
                $newValue->content_entry_id = $newEntry->id;
                $newValue->push();

                // media relations
                $fv->mediaRelations->each(function($mr) use ($newValue){
                    $newMr = $mr->replicate(['field_value_id']);
                    $newMr->field_value_id = $newValue->id;
                    $newMr->push();
                });

                // value relations (relation field)
                $fv->valueRelations->each(function($vr) use ($newValue){
                    $newVr = $vr->replicate(['field_value_id']);
                    $newVr->field_value_id = $newValue->id;
                    $newVr->push();
                });
            });

            return $newEntry;
        });

        return response()->json([
            'message'   => 'Content duplicated',
            'entry_id'  => $newEntry->id,
        ], 201);
    }
}
