<?php

namespace App\Http\Controllers\Admin;

use App\Helpers\ApiResponse;
use App\Helpers\CacheHelper;
use App\Http\Controllers\Controller;
use App\Models\AdditionalActivity;
use App\Models\Archive;
use App\Models\Form;
use App\Models\FormSubmission;
use App\Models\Franchisee;
use App\Models\FranchiseeGroup;
use App\Models\Page;
use App\Models\PageTemplate;
use App\Models\PageTranslationSubmission;
use App\Models\Payment;
use App\Models\PaymentInvoice;
use App\Models\PaymentMethod;
use App\Models\Program;
use App\Models\Setting;
use App\Models\Teacher;
use App\Models\Testimonial;
use App\Models\TranslatedPage;
use App\Models\User;
use App\Services\SlugScoped\SlugScopedPersistenceService;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;
use Symfony\Component\HttpFoundation\Response;

class TrashController extends Controller
{
    public function __construct(
        private readonly SlugScopedPersistenceService $slugScopedPersistenceService,
    ) {
    }

    protected function resolveModel(string $type): string
    {
        $map = [
            'App\Models\Program' => Program::class,
            'App\Models\Testimonial' => \App\Models\Testimonial::class,
            'App\Models\Page' => Page::class,
            'App\Models\Form' => \App\Models\Form::class,
            'App\Models\Teacher' => \App\Models\Teacher::class,
            'App\Models\AdditionalActivity' => AdditionalActivity::class,
            'App\Models\FormSubmission' => \App\Models\FormSubmission::class,
            'App\Models\PageTemplate' => \App\Models\PageTemplate::class,
            'App\Models\FranchiseeGroup' => \App\Models\FranchiseeGroup::class,
            'App\Models\PageTranslationSubmission' => \App\Models\PageTranslationSubmission::class,
            'App\Models\Payment' => \App\Models\Payment::class,
            'App\Models\PaymentMethod' => \App\Models\PaymentMethod::class,
            'App\Models\Setting' => \App\Models\Setting::class,
            'App\Models\TranslatedPage' => \App\Models\TranslatedPage::class,
            'App\Models\User' => \App\Models\User::class,
            'App\Models\PaymentInvoice' => \App\Models\PaymentInvoice::class,
        ];

        if (isset($map[$type])) {
            return $map[$type];
        }

        if (in_array($type, $map, true)) {
            return $type;
        }

        throw new InvalidArgumentException('Model type not found');
    }

    public function trashList(Request $request)
    {
        $auth = Auth::user();
        $perPage = $request->get('per_page', 15);
        $allowedSorts = ['created_at', 'updated_at'];
        $sortBy = in_array($request->get('sort_by'), $allowedSorts, true)
            ? $request->get('sort_by')
            : 'created_at';
        $sortOrder = $request->get('sort_order');
        $sortOrder = $sortOrder == '1' ? 'asc' : ($sortOrder == '-1' ? 'desc' : 'desc');
        $search = $request->get('search', '');

        try {
            $cacheKey = 'archives_' . md5(json_encode([
                'role' => $auth->role,
                'franchisee_id' => $auth->franchisee_id,
                'search' => $search,
                'sort_by' => $sortBy,
                'sort_order' => $sortOrder,
                'per_page' => $perPage,
                'page' => $request->get('page', 1),
            ]));

            $archives = CacheHelper::rememberByTag('archives', $cacheKey, function () use ($auth, $sortBy, $sortOrder, $search, $perPage) {
                $query = Archive::query();

                if ($auth->role !== 'super_admin') {
                    $query->where('franchisee_id', $auth->franchisee_id);
                } else {
                    $query->whereNull('franchisee_id');
                }

                if (!empty($search)) {
                    $query->whereRaw('data::text ILIKE ?', ["%{$search}%"]);
                }

                return $query->orderBy($sortBy, $sortOrder)->paginate($perPage);
            });

            return ApiResponse::success($archives, 'Trash list fetched successfully');
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    public function restore(Request $request, $id)
    {
        $auth = Auth::user();

        try {
            $modelClass = $this->resolveModel((string) $request->input('type'));
            $replaceExisting = $request->boolean('replace_existing');

            $item = $this->findTrashedItem($modelClass, $id, $auth);

            if (!$item->trashed()) {
                return ApiResponse::error('Record is not in trash', Response::HTTP_NOT_FOUND);
            }

            $archive = Archive::where('archivable_type', $modelClass)
                ->where('archivable_id', (string) $item->getKey())
                ->latest()
                ->first();

            $archiveData = $archive?->data;

            $result = DB::transaction(function () use ($modelClass, $item, $replaceExisting, $archiveData) {
                if ($this->slugScopedPersistenceService->supports($modelClass) && !empty($item->slug)) {
                    return $this->slugScopedPersistenceService->restoreFromTrash(
                        $item,
                        $replaceExisting,
                        is_array($archiveData) ? $archiveData : null,
                    );
                }

                $item->restore();
                Archive::where('archivable_type', $modelClass)
                    ->where('archivable_id', (string) $item->getKey())
                    ->delete();

                return new \App\Services\SlugScoped\SlugPersistResult($item->fresh(), true, false);
            });

            CacheHelper::clearByTag('archives');
            $this->clearEntityCache($modelClass);

            $message = $result->wasReplaced
                ? class_basename($modelClass) . ' restored and replaced the existing live record'
                : class_basename($modelClass) . ' restored successfully';

            return ApiResponse::successWithMeta($result->model, $message, $result->meta());
        } catch (InvalidArgumentException $e) {
            return ApiResponse::error($e->getMessage(), Response::HTTP_NOT_FOUND);
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    public function forceDelete(Request $request, $id)
    {
        $auth = Auth::user();

        try {
            $modelClass = $this->resolveModel((string) $request->input('type'));

            DB::beginTransaction();

            $item = $this->findTrashedItem($modelClass, $id, $auth);

            if (!$item->trashed()) {
                DB::rollBack();

                return ApiResponse::error(
                    'Record must be deleted first before permanent delete',
                    Response::HTTP_NOT_FOUND,
                );
            }

            $itemId = $item->getKey();
            $item->forceDelete();

            Archive::where('archivable_type', $modelClass)
                ->where('archivable_id', (string) $itemId)
                ->delete();

            DB::commit();

            CacheHelper::clearByTag('archives');
            $this->clearEntityCache($modelClass);

            return ApiResponse::success(null, class_basename($modelClass) . ' permanently deleted successfully');
        } catch (InvalidArgumentException $e) {
            DB::rollBack();

            return ApiResponse::error($e->getMessage(), Response::HTTP_NOT_FOUND);
        } catch (\Throwable $e) {
            DB::rollBack();

            return ApiResponse::exception($e);
        }
    }

    public function bulkRestore(Request $request, $type)
    {
        try {
            $modelClass = $this->resolveModel($type);
            $auth = Auth::user();

            $query = $modelClass::onlyTrashed()->whereIn('id', $request->ids ?? []);
            if ($auth->role !== 'super_admin') {
                $query->where('franchisee_id', $auth->franchisee_id);
            }

            $query->restore();

            CacheHelper::clearByTag('archives');

            return response()->json(['message' => 'Bulk restore successful']);
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    public function bulkForceDelete(Request $request, $type)
    {
        try {
            $modelClass = $this->resolveModel($type);
            $auth = Auth::user();

            $query = $modelClass::onlyTrashed()->whereIn('id', $request->ids ?? []);
            if ($auth->role !== 'super_admin') {
                $query->where('franchisee_id', $auth->franchisee_id);
            }

            $query->forceDelete();

            CacheHelper::clearByTag('archives');

            return response()->json(['message' => 'Bulk delete successful']);
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    public function archiveLogs(Request $request)
    {
        $logs = Archive::where('franchisee_id', auth()->user()->franchisee_id)
            ->latest()
            ->paginate(10);

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

    private function findTrashedItem(string $modelClass, string $id, $auth): Model
    {
        $query = $modelClass::withTrashed()->where('id', $id);

        if ($auth->role !== 'super_admin') {
            $query->where('franchisee_id', $auth->franchisee_id);
        }

        return $query->firstOrFail();
    }

    private function clearEntityCache(string $modelClass): void
    {
        $tags = [
            Program::class => 'programs',
            AdditionalActivity::class => 'additional_activities',
            Page::class => 'pages',
            Form::class => 'forms',
            Teacher::class => 'teachers',
            User::class => 'users',
            Testimonial::class => 'testimonials',
            PageTemplate::class => 'templates',
            FranchiseeGroup::class => 'franchisee_groups',
            Setting::class => 'setting',
            FormSubmission::class => 'submission_forms',
            Franchisee::class => 'franchisees',
            Payment::class => 'payments',
            PaymentMethod::class => 'payment_methods',
            PaymentInvoice::class => 'payment_invoices',
            PageTranslationSubmission::class => 'page_translation_submissions',
            TranslatedPage::class => 'translated_pages',
        ];

        if (isset($tags[$modelClass])) {
            CacheHelper::flushRedisTag($tags[$modelClass]);
        }
    }
}
