<?php

namespace $CLASS_NAMESPACE$;

use App\Enums\StatusEnum;
use $MODULE_NAMESPACE$\$MODULE$\Models\$STUDLY_NAME$;
use $MODULE_NAMESPACE$\$MODULE$\Transformers\$STUDLY_NAME$Resource;
use Illuminate\Support\Collection;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Services\Export\CsvExporter;
use App\Services\Export\PdfExporter;
use App\Services\HasPaginated;


class $CLASS$
{
    use HasPaginated;

    public function baseQuery(array $params)
    {
        $filterParams = collect($params)
            ->except(['per_page', 'page', 'sort_by', 'sort_dir'])
            ->toArray();
        $builder = $STUDLY_NAME$::query()->filter($filterParams);
        // If explicit show_deleted flag present, include trashed
        if (! empty($params['show_deleted']) || (isset($filterParams['status']) && str_contains((string) $filterParams['status'], 'deleted'))) {
            $builder->withTrashed();
        }
        return $builder;
    }

    public function all(array $params)
    {
        $query = $STUDLY_NAME$::orderBy('id', 'desc')
            ->filter($params); // ← Let eloquent-filter handle filtering

        // Handle soft deletes
        if (!empty($params['show_deleted']) || (isset($params['status']) && str_contains((string) $params['status'], 'deleted'))) {
            $query->withTrashed();
        }

        // Handle sorting
        if (!empty($params['sort_by'])) {

            $query->orderBy($params['sort_by'], $params['sort_dir'] ?? 'asc');
        }

        return $query->paginate(
            $params['per_page'] ?? 10,
            ['*'],
            'page',
            $params['page'] ?? 1
        );
    }


    /**
     * Extract and sanitize pagination + filter params from request
     */
    public function paginateParams($request): array
    {
        $params = [
            'search' => $request->input('search'),
            'per_page' => (int) $request->input('per_page', 10),
            'page' => (int) $request->input('page', 1),
            'category' => $request->input('category'),
            'status' => $request->input('status'),
            'created_at_start' => $request->input('created_at_start'),
            'created_at_end' => $request->input('created_at_end'),
            'sort_by' => $request->input('sort_by', 'id'),
            'sort_dir' => $request->input('sort_dir', 'desc'),
        ];

        // Filter out null values
        return array_filter($params, function($value) {
            return $value !== null && $value !== '';
        }) + [
            'sort_by' => 'id',
            'sort_dir' => 'desc',
            'per_page' => 10,
            'page' => 1,
        ];
    }

    /**
     * Get a single record by its ID.
     */
    public function getById($id)
    {
        return $STUDLY_NAME$::find($id);
    }

    /**
     * Create a new record.
     */
    public function create(array $data)
    {
        try {
            DB::beginTransaction();

            $item = $STUDLY_NAME$::create($data);

            // Log activity
            $actor = auth()->user();
            $item->logActivity(
                action: '$LOWER_NAME$_created',
                metadata: [
                    'title' => $item->title,
                    'description' => $item->description,
                    'status' => $item->status,
                    'actor_id' => $actor?->id,
                    'actor_email' => $actor?->email ?? 'system@local',
                    'event' => 'created',
                ],
                description: "$STUDLY_NAME$ {$item->title} created by ".($actor?->name ?? 'System'),
                title: '$STUDLY_NAME$ Created',
                relationType: $STUDLY_NAME$::class,
                relationId: $item->id
            );

            DB::commit();
            return $item;
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * Update an existing record.
     */
    public function update($id, array $data)
    {
        try {
            DB::beginTransaction();

            $record = $this->getById($id);

            if (!$record) {
                DB::rollBack();
                return null;
            }

            $original = $record->toArray();
            $record->update($data);

            // Log activity with changes
            $changes = [];
            foreach ($data as $key => $value) {
                if (isset($original[$key]) && $original[$key] != $value) {
                    $changes[$key] = ['old' => $original[$key], 'new' => $value];
                }
            }

            if (!empty($changes)) {
                $actor = auth()->user();
                $record->logActivity(
                    action: '$LOWER_NAME$_updated',
                    metadata: [
                        'changes' => $changes,
                        'title' => $record->title,
                        'actor_id' => $actor?->id,
                        'actor_email' => $actor?->email ?? 'system@local',
                        'event' => 'updated',
                    ],
                    description: "$STUDLY_NAME$ {$record->title} updated by ".($actor?->name ?? 'System'),
                    title: '$STUDLY_NAME$ Updated',
                    relationType: $STUDLY_NAME$::class,
                    relationId: $record->id
                );
            }

            DB::commit();
            return $record;
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * Delete a record by its ID.
     */
    public function delete($id)
    {
        try {
            DB::beginTransaction();

            $record = $this->getById($id);

            if (!$record) {
                DB::rollBack();
                return false;
            }

            // Log activity before deletion
            $actor = auth()->user();
            $record->logActivity(
                action: '$LOWER_NAME$_deleted',
                metadata: [
                    'title' => $record->title,
                    'description' => $record->description,
                    'status' => $record->status,
                    'actor_id' => $actor?->id,
                    'actor_email' => $actor?->email ?? 'system@local',
                    'event' => 'deleted',
                ],
                description: "$STUDLY_NAME$ {$record->title} deleted by ".($actor?->name ?? 'System'),
                title: '$STUDLY_NAME$ Deleted',
                relationType: $STUDLY_NAME$::class,
                relationId: $record->id
            );

            $record->delete();

            DB::commit();
            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * Centralized query building method to eliminate code duplication
     */
    public function buildQuery(array $params)
    {
        return $STUDLY_NAME$::query()
            ->when($params['search'] ?? null, function ($query, $search) {
                $query->where(function ($q) use ($search) {
                    $q->where('title', 'like', "%{$search}%")
                      ->orWhere('description', 'like', "%{$search}%");
                });
            })
            ->when($params['status'] ?? null, function ($query, $status) {
                // Handle multiple status values (comma-separated)
                if (str_contains($status, ',')) {
                    $statuses = array_map('trim', explode(',', $status));
                    $query->whereIn('status', $statuses);
                } else {
                    $query->where('status', $status);
                }
            })
            ->when($params['category'] ?? null, function ($query, $category) {
                $query->where('category', $category);
            })
            ->when($params['created_at_start'] ?? null, function ($query, $start) {
                $query->whereDate('created_at', '>=', $start);
            })
            ->when($params['created_at_end'] ?? null, function ($query, $end) {
                $query->whereDate('created_at', '<=', $end);
            });
    }

    public function statuses()
    {
        return collect(StatusEnum::taskStatuses())
            ->map(fn($status) => [
                'label' => ucfirst(strtolower($status->name)),
                'value' => $status->value,
            ])
            ->values();
    }

    public function summary(array $params): array
    {
        $query = $this->baseQuery($params);
        $total = $query->count();

        $counts = $query
            ->selectRaw('
            COUNT(CASE WHEN status = ? THEN 1 END) as active_$LOWER_NAME$s,
            COUNT(CASE WHEN status = ? THEN 1 END) as inactive_$LOWER_NAME$s,
            COUNT(CASE WHEN DATE(created_at) = CURDATE() THEN 1 END) as created_today,
            COUNT(CASE WHEN YEAR(created_at) = YEAR(NOW()) AND MONTH(created_at) = MONTH(NOW()) THEN 1 END) as created_this_month
        ', [
                StatusEnum::ACTIVE->value,
                StatusEnum::INACTIVE->value,
            ])
            ->first();

        return [
            ['title' => 'Total $STUDLY_NAME$s', 'value' => $total],
            ['title' => 'Active', 'value' => $counts->active_$LOWER_NAME$s ?? 0],
            ['title' => 'Inactive', 'value' => $counts->inactive_$LOWER_NAME$s ?? 0],
            ['title' => 'Created Today', 'value' => $counts->created_today ?? 0],
            ['title' => 'Created This Month', 'value' => $counts->created_this_month ?? 0],
        ];
    }

    /**
     * Export functionality - Get data for export with chunking
     */
    public function getExportData(array $columns, int $chunkSize = 500, ?array $ids = null): iterable
    {
        $with = [];
        foreach ($columns as $col) {
            if (str_contains($col, '.')) {
                $with[] = explode('.', $col)[0];
            }
        }
        $with = array_unique($with);

        $query = $STUDLY_NAME$::with($with);
        if ($ids) {
            $query = $query->whereIn('id', $ids);
        }

        for ($page = 1; ; $page++) {
            $chunk = $query->skip(($page - 1) * $chunkSize)->take($chunkSize)->get();
            if ($chunk->isEmpty()) {
                break;
            }
            foreach ($chunk as $item) {
                yield $item;
            }
        }
    }

    /**
     * Transform row data for export
     */
    public function transformExportRow($item, array $columns): array
    {
        $row = [];
        foreach ($columns as $col) {
            if ($col === 'status') {
                $row[$col] = ucfirst(strtolower($item->status ?? ''));
            } elseif ($col === 'created_at') {
                $row[$col] = $item->created_at ? $item->created_at->format('Y-m-d H:i:s') : '';
            } elseif ($col === 'updated_at') {
                $row[$col] = $item->updated_at ? $item->updated_at->format('Y-m-d H:i:s') : '';
            } elseif (str_contains($col, '.')) {
                [$relation, $field] = explode('.', $col, 2);
                $related = $item->$relation;
                // Handle single or collection relation
                if ($related instanceof Collection) {
                    $row[$col] = $related->pluck($field)->implode(', ');
                } else {
                    $row[$col] = $related ? ($related->$field ?? '') : '';
                }
            } else {
                $row[$col] = $item->{$col} ?? '';
            }
        }

        return $row;
    }

    /**
     * Export $LOWER_NAME$s to CSV/PDF
     */
    public function export(Request $request)
    {
        try {
            $data = $request->validate([
                'ids' => 'array',
                'ids.*' => 'integer',
                'data.columns' => 'array',
                'data.columns.*' => 'string',
                'data.format' => 'string|in:csv,pdf',
                'select_all' => 'boolean',
                'filters' => 'array',
            ]);

            $columns = $data['data']['columns'] ?? ['title', 'description', 'status'];
            $format = $data['data']['format'] ?? 'csv';
            $ids = $data['ids'] ?? [];

            // Handle select_all functionality
            if ($request->boolean('select_all')) {
                $filters = $request->input('filters', []);
                $queryParams = array_merge($filters, ['per_page' => null, 'page' => null]);
                $query = $this->buildQuery($queryParams);
                $max = (int) config('bulk_actions.max_select_all', 25000);
                $allIds = [];
                $query->select('id')->chunk(1000, function ($chunk) use (&$allIds, $max) {
                    foreach ($chunk as $item) {
                        $allIds[] = $item->id;
                        if (count($allIds) >= $max) {
                            return false; // break out early
                        }
                    }
                });
                $ids = $allIds;
            }

            // Direct export using service methods
            if (count($ids) < 10000) {
                $exporter = match ($format) {
                    'csv' => new CsvExporter,
                    'pdf' => new PdfExporter,
                    default => throw new \InvalidArgumentException('Unsupported export format: '.$format),
                };

                $rawData = $this->getExportData($columns, 500, $ids);

                $data = [];
                foreach ($rawData as $item) {
                    $data[] = $this->transformExportRow($item, $columns);
                }

                $filename = '$STUDLY_NAME$s-'.now()->format('Y-m-d_H-i-s').'.'.$format;
                $relativePath = 'exports/'.$filename;
                $path = storage_path('app/public/'.$relativePath);

                // Ensure export directory exists
                if (! is_dir(dirname($path))) {
                    mkdir(dirname($path), 0777, true);
                }

                $exporter->export($data, $columns, $path, $format);
                // Public URL via storage symlink
                $fileUrl = asset('storage/'.$relativePath);

                return response()->json([
                    'success' => true,
                    'message' => 'Export completed successfully',
                    'export' => [
                        'file_url' => $fileUrl,
                        'status' => 'COMPLETED',
                    ],
                ]);
            } else {
                // For large exports, you could implement background processing here
                return response()->json([
                    'success' => true,
                    'message' => 'Export is too large. Please refine your selection.',
                    'export' => null,
                ]);
            }
        } catch (\Exception $e) {
            debug_log('Error ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Export failed: ' . $e->getMessage(),
                'export' => null,
            ], 500);
        }
    }

    /**
     * Import $LOWER_NAME$s
     */
    public function import(Request $request): string
    {
        return '$STUDLY_NAME$ import functionality placeholder';
    }

    /**
     * Download exported file
     */
    public function download($filename)
    {
        $path = 'exports/' . $filename;

        if (!Storage::disk('public')->exists($path)) {
            abort(404, 'File not found');
        }

        $content = Storage::disk('public')->get($path);
        $mimeType = Storage::disk('public')->mimeType($path);

        // Clean up the file after download
        Storage::disk('public')->delete($path);

        return Response::make($content, 200, [
            'Content-Type' => $mimeType,
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ]);
    }

    /**
     * Update status for a single $LOWER_NAME$
     */
    public function updateStatus($id, string $status)
    {
        try {
            DB::beginTransaction();

            $$LOWER_NAME$ = $this->getById($id);

            if (!$$LOWER_NAME$) {
                DB::rollBack();
                return null;
            }

            $oldStatus = $$LOWER_NAME$->status;
            $$LOWER_NAME$->update(['status' => $status]);

            // Log activity
            $actor = auth()->user();
            $$LOWER_NAME$->logActivity(
                action: '$LOWER_NAME$_status_updated',
                metadata: [
                    'old_status' => $oldStatus,
                    'new_status' => $status,
                    'title' => $$LOWER_NAME$->title,
                    'actor_id' => $actor?->id,
                    'actor_email' => $actor?->email ?? 'system@local',
                    'event' => 'status_updated',
                ],
                description: "$STUDLY_NAME$ {$$LOWER_NAME$->title} status changed from {$oldStatus} to {$status} by ".($actor?->name ?? 'System'),
                title: '$STUDLY_NAME$ Status Updated',
                relationType: $STUDLY_NAME$::class,
                relationId: $$LOWER_NAME$->id
            );

            DB::commit();
            return $$LOWER_NAME$->fresh();
        } catch (\Exception $e) {
            DB::rollBack();
            debug_log('Error ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Bulk update status for multiple $LOWER_NAME$s
     */
    public function bulkStatusUpdate(string $status, array $ids): array
    {
        try {
            DB::beginTransaction();

            if (empty($ids)) {
                DB::rollBack();
                return ['count' => 0, 'ids' => []];
            }

            // Update all $LOWER_NAME$s
            $updated = $STUDLY_NAME$::whereIn('id', $ids)->update(['status' => $status]);

            // Log activity for each $LOWER_NAME$
            $$LOWER_NAME$s = $STUDLY_NAME$::whereIn('id', $ids)->get();
            $actor = auth()->user();
            foreach ($$LOWER_NAME$s as $$LOWER_NAME$) {
                $$LOWER_NAME$->logActivity(
                    action: '$LOWER_NAME$_bulk_status_updated',
                    metadata: [
                        'new_status' => $status,
                        'title' => $$LOWER_NAME$->title,
                        'bulk_count' => count($ids),
                        'actor_id' => $actor?->id,
                        'actor_email' => $actor?->email ?? 'system@local',
                        'event' => 'bulk_status_updated',
                    ],
                    description: "$STUDLY_NAME$ {$$LOWER_NAME$->title} status updated to {$status} via bulk action by ".($actor?->name ?? 'System'),
                    title: '$STUDLY_NAME$ Bulk Status Updated',
                    relationType: $STUDLY_NAME$::class,
                    relationId: $$LOWER_NAME$->id
                );
            }

            DB::commit();

            return [
                'count' => $updated,
                'ids' => $ids,
                'status' => $status,
            ];
        } catch (\Exception $e) {
            DB::rollBack();
            debug_log('Error ' . $e->getMessage());
            throw $e;
        }
    }
}
