<?php

namespace App\Http\Controllers\api;

use App\Http\Controllers\Controller;
use App\Http\Requests\GetApiRequest;
use App\Models\Art;
use App\Models\Book;
use App\Models\Branch;
use App\Models\Category;
use App\Models\Chapter;
use App\Models\Division;
use App\Models\Gate;
use App\Models\Law;
use App\Models\LikeArt;
use App\Models\Note;
use App\Models\Part;
use App\Models\Section;
use App\Models\Volum;
use App\Traits\BaseApiResponse;
use Illuminate\Http\Request;

class ArtController extends Controller
{
    use BaseApiResponse;

    public function index(GetApiRequest $request)
    {
        $arts = Art::with(['chapter', 'part', 'volum', 'law', 'book', 'section', 'gate'])->where('book_id', $request->book_id)->orderBy('number')->get();

        $arts = $arts->map(function ($art) {
            return [
                'id' => $art->id,
                'text' => $art->text,
                'number' => $art->number,
                'chapter' => $art->chapter != null ? [
                    'id' => $art->chapter->id,
                    'title' => $art->chapter->title,
                    'number' => $art->chapter->number,
                ] : null,
                'part' => $art->part != null ? [
                    'id' => $art->part->id,
                    'title' => $art->part->title,
                    'number' => $art->part->number,
                ] : null,
                'volum' => $art->volum != null ? [
                    'id' => $art->volum->id,
                    'title' => $art->volum->title,
                    'number' => $art->volum->number,
                ] : null,
                'law' => $art->law != null ? [
                    'id' => $art->law->id,
                    'title' => $art->law->title,
                    'number' => $art->law->number,
                ] : null,
                'book' => $art->book != null ? [
                    'id' => $art->book->id,
                    'title' => $art->book->title,
                    'number' => $art->book->number,
                ] : null,
                'section' => $art->section != null ? [
                    'id' => $art->section->id,
                    'title' => $art->section->title,
                    'number' => $art->section->number,
                ] : null,
                'gate' => $art->gate != null ? [
                    'id' => $art->gate->id,
                    'title' => $art->gate->title,
                    'number' => $art->gate->number,
                ] : null,
            ];
        });

        return response()->json(['arts' => $arts]);
    }

    public function single($id)
    {
        $art = Art::select('id', 'title', 'number', 'text', 'law_id')->find($id);

        if (!$art) {
            return $this->failed([], 'Art not found');
        }

        $law = Law::find($art?->law_id);

        $art->is_like = $this->isLiked($art->id);
        $art->note = Note::select('id', 'note', 'color_code','created_at')->where('user_id', auth()->user()->id)->where('art_id', $id)->get();
        $art->category = $law?->category?->name;
        $art->route = array_values($this->route(Art::class, $art));

        $previousArt = Art::select('id', 'title', 'number', 'text', 'law_id')
            ->where('law_id',$art->law_id)
            ->where('number', '<', $art->number)
            ->orderBy('number', 'desc')
            ->first();

        if ($previousArt) {
            $previousLaw = Law::find($previousArt->law_id);
            $previousArt->is_like = $this->isLiked($previousArt->id);
            $previousArt->note = Note::select('id', 'note', 'color_code')->where('user_id', auth()->user()->id)->where('art_id', $previousArt->id)->get();
            $previousArt->category = $previousLaw?->category?->name;
            $previousArt->route = array_values($this->route(Art::class, $previousArt));
        }

        $nextArt = Art::select('id', 'title', 'number', 'text', 'law_id')
            ->where('law_id',$art->law_id)
            ->where('number', '>', $art->number)
            ->orderBy('number')
            ->first();

        if ($nextArt) {
            $nextLaw = Law::find($nextArt->law_id);
            $nextArt->is_like = $this->isLiked($nextArt->id);
            $nextArt->note = Note::select('id', 'note', 'color_code')->where('user_id', auth()->user()->id)->where('art_id', $nextArt->id)->get();
            $nextArt->category = $nextLaw?->category?->name;
            $nextArt->route = array_values($this->route(Art::class, $nextArt));
        }

        $results = array_values(array_filter([$previousArt, $art, $nextArt]));

        return $this->success($results);
    }

    public function like(Art $art)
    {
        $userId = auth()->id();

        $existingLike = LikeArt::query()->where('art_id', $art->id)
            ->where('user_id', $userId)
            ->first();

        if ($existingLike) {
            $existingLike->delete();

            return $this->success(null, 'Success', 'Art unliked successfully');
        }

        LikeArt::create([
            'art_id' => $art->id,
            'user_id' => $userId,
        ]);

        return $this->success(null, 'Success', 'Art liked successfully');
    }


    private function isLiked($art_id): bool
    {
        return LikeArt::query()->where('art_id', $art_id)
            ->where('user_id', auth()->user()->id)
            ->exists();
    }

    public function likes()
    {
        $likes = LikeArt::query()->where('user_id', auth()->user()->id)
            ->with('art')
            ->get()
            ->map(function ($q) {
                return [
                    'id' => $q->art->id,
                    'title' => $q->art->title,
                    'text' => $q->art->text
                ];
            });

        return $this->success($likes);
    }


    public function search(Request $request)
    {
        $validated = $request->validate([
            'book_id' => 'nullable|array',
            'volume_id' => 'nullable|array',
            'division_id' => 'nullable|array',
            'section_id' => 'nullable|array',
            'part_id' => 'nullable|array',
            'gate_id' => 'nullable|array',
            'law_id' => 'nullable|array',
            'chapter_id' => 'nullable|array',
            'branch_id' => 'nullable|array',
            'category_id' => 'nullable|int',
            'per_page' => 'nullable|integer',
            'search' => 'nullable|string'
        ]);

        $models = [
            Law::class,
            Volum::class,
            Book::class,
            Division::class,
            Section::class,
            Chapter::class,
            Part::class,
            Gate::class,
            Branch::class,
            Art::class
        ];

        $results = [];

        foreach ($models as $modelClass) {
            $results = array_merge($results, $this->searchModel($modelClass, $validated));
        }

        return $this->success($results);
    }

    private function searchModel($modelClass, $validated)
    {
        $query = $modelClass::query();

        $filters = [
            'law_id',
            'volume_id',
            'division_id',
            'section_id',
            'part_id',
            'gate_id',
            'chapter_id',
            'branch_id'
        ];

        $model = new $modelClass;
        if ($model->getTable() == 'art') {
            $query->where(function ($query) use ($validated, $filters) {
                if (!empty($validated['search'])) {
                    $query->where(function ($q) use ($validated) {
                        $q->where('title', 'LIKE', "%{$validated['search']}%")
                            ->orWhere('text', 'LIKE', "%{$validated['search']}%");
                    });
                }

                foreach ($filters as $filter) {
                    if (!empty($validated[$filter])) {
                        $query->whereIn($filter, $validated[$filter]);
                    }
                }
            });


            if (!empty($validated['category_id'])) {
                $query->whereIn('law_id', Category::where('type', $this->convertValueTo($validated['category_id']))->get()->pluck('id'));
            }

            $items = $query->paginate($validated['per_page'] ?? 10);

            return $items->map(function ($item) use ($validated, $modelClass) {
                $text = $item->text ?? '';
                $search = preg_quote($validated['search'] ?? '', '/');
                if (!empty($text) && preg_match('/\b(.{0,50})\b(' . $search . ')\b(.{0,50})\b/i', $text, $matches)) {
                    $context = trim($matches[1] ?? '') . ' ' . $matches[2] . ' ' . trim($matches[3] ?? '');
                } else {
                    $context = $text;
                }

                $law = Law::find($item->law_id);

                return [
                    'id' => $item->id,
                    'title' => $item->title,
                    'text' => $context,
                    'is_locked' => auth()->user()->isSubscriber()  !== false ? false : optional($law)->is_locked,
                    'type' => 'art',
                    'route' => array_values($this->route($modelClass, $item)),
                    'category' => optional($law->category)->name,
                    'law' => $law?->title,
                    'count_art' => $law->arts->count(),
                    'count_volums' => $law->volums->count(),
                    'price' => $law->price,
                    'image' => $law->image
                ];
            })->toArray();
        } else {
            $query = $query->where('title', 'LIKE', '%' . ($validated['search'] ?? '') . '%');
        }

        $items = $query->paginate($validated['per_page'] ?? 10);

        return $items->map(function ($item) use ($modelClass) {
            $law = Law::find($item?->law_id ?? $item->id);
            if ((new $modelClass)->getTable() == 'laws') {
                return [
                    'id' => $item->id,
                    'title' => $item->title,
                    'number' => $item->number,
                    'type' => (new $modelClass)->getTable(),
                    'is_locked' => auth()->user()->isSubscriber()  !== false ? false : optional($law)->is_locked,
                    'route' => array_values($this->route($modelClass, $item)),
                    'category' => optional($law?->category)?->name ?? '',
                    'image' => $law->image
                ];
            } else if ((new $modelClass)->getTable() == 'art') {
                return [
                    'id' => $item->id,
                    'title' => $item->title,
                    'number' => $item->number,
                    'type' => (new $modelClass)->getTable(),
                    'is_locked' => auth()->user()->isSubscriber()  !== false ? false : optional($law)->is_locked,
                    'route' => array_values($this->route($modelClass, $item)),
                    'law' => $law?->title ?? '',
                    'image' => $law->image
                ];
            } else {
                return [
                    'id' => $item->id,
                    'title' => $item->title,
                    'number' => $item->number,
                    'type' => (new $modelClass)->getTable(),
                    'is_locked' => auth()->user()->isSubscriber()  !== false ? false : optional($law)->is_locked,
                    'route' => array_values($this->route($modelClass, $item)),
                    'law' => $law?->title ?? '',
                ];
            }
        })->toArray();
    }



    private function route($modelClass, $query)
    {
        if ((new $modelClass)->getTable() == 'art') {
            $route = array_filter([
                Law::find($query->law_id)?->title,
                Volum::find($query->volum_id)?->title,
                Book::find($query->book_id)?->title,
                Division::find($query->division_id)?->title,
                Section::find($query->section_id)?->title,
                Chapter::find($query->chapter_id)?->title,
                Part::find($query->part_id)?->title,
                Gate::find($query->gate_id)?->title,
                Branch::find($query->branch_id)?->title
            ]);

            $route = array_values($route);
            return $route;
        }
        return [];
    }

    public function fash_search(Request $request)
    {
        $search = $request->input('search');

        $models = [
            Law::class,
            Art::class
        ];

        $results = [];

        foreach ($models as $modelClass) {
            $results = array_merge($results, $this->searchModelFastSearch($modelClass, $search));
        }


        $models_other = [
            Volum::class,
            Book::class,
            Division::class,
            Section::class,
            Chapter::class,
            Part::class,
            Gate::class,
            Branch::class,
        ];

        $found = false;
        foreach ($models_other as $modelClass) {
            if (count($this->searchModelFastSearch($modelClass, $search)) > 0 && !$found) {
                $results = array_merge($results, $this->searchModelFastSearch($modelClass, $search));
                $found = true;
            }
        }


        $models = [
            Law::class,
            Volum::class,
            Book::class,
            Division::class,
            Section::class,
            Chapter::class,
            Part::class,
            Gate::class,
            Branch::class,
            Art::class
        ];

        $count_all = 0;

        foreach ($models as $modelClass) {
            $count_all += count($this->searchModel($modelClass, $search));
        }


        return $this->success(['items' => $results, 'count' => $count_all]);
    }

    private function searchModelFastSearch($modelClass, $search)
    {
        $results = $modelClass::searchLimit($search);

        return $results->map(function ($q) use ($modelClass, $search) {
            $instance = new $modelClass;
            $table = $instance->getTable();

            if ($table === 'art') {
                return $this->formatArtResult($q, $search);
            }

            return $this->formatGenericResult($q, $table);
        })->toArray();
    }

    private function formatGenericResult($q, $table)
    {
        $category = null;
        if ($table === 'laws') {
            $category = Law::where('id', $q->id)->first()?->category?->name;
        } else {
            $category = Law::where('id', $q->law_id)->first()?->category?->name;
        }

        if ($table !== 'laws') {
            return [
                'id' => $q->id,
                'title' => $q->title,
                'type' => $table === 'section' ? 'sections' : $table,
                'category' => $category,
                'law' => Law::where('id', $q->law_id)->first()?->title
            ];
        }

        return [
            'id' => $q->id,
            'title' => $q->title,
            'type' => $table === 'section' ? 'sections' : $table,
            'category' => $category,
            'image' => Law::where('id', $q->id)->first()?->image
        ];
    }

    private function formatArtResult($q, $search)
    {
        $law = Law::where('id', $q->law_id)->first();
        $route = array_filter([
            $law?->title,
            Volum::find($q->volum_id)?->title,
            Book::find($q->book_id)?->title,
            Division::find($q->division_id)?->title,
            Section::find($q->section_id)?->title,
            Chapter::find($q->chapter_id)?->title,
            Part::find($q->part_id)?->title,
            Gate::find($q->gate_id)?->title,
            Branch::find($q->branch_id)?->title
        ]);

        $text = $q->text;
        $search = preg_quote($search, '/');
        if (preg_match('/\b(.{0,50})\b(' . $search . ')\b(.{0,50})\b/i', $text, $matches)) {
            $context = trim($matches[1]) . ' ' . $matches[2] . ' ' . trim($matches[3]);
        } else {
            $context = $text;
        }

        return [
            'id' => $q->id,
            'title' => $q->title,
            'text' => $context,
            'is_locked' => auth()->user()->isSubscriber()  !== false ? false : $law->is_locked,
            'type' => 'art',
            'route' => $route,
            'category' => $law?->category?->name,
            'law' => $law?->title,
            'count_art' => $law->arts->count(),
            'count_volum' => $law->volums->count(),
            'price' => $law->price,
            'image' => $law->image
        ];
    }

    private function convertValueTo($var)
    {
        switch ($var) {
            case 1:
                return 'hagigi';
                break;
            case 2:
                return 'kifari';
                break;

            default:
                return 'kifari';
                break;
        }
    }
}
