<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

use App\Models\Tag;
use Illuminate\Support\Str;
use Illuminate\Support\Arr;
use App\Http\Requests\TagValidation;
use Illuminate\Database\Eloquent\Relations\MorphTo;

use App\Models\Announcement;
use App\Models\Blog;
use App\Models\Course;
use App\Models\Page;
use App\Models\ContentElement;
use App\Models\Livestream;
use App\Models\StaffProfile;

class TagsController extends Controller
{
    public function index()
    {
        if (!auth()->user()->can('viewAny', Tag::class)) {
            return redirect('/')->with('error', 'You do not have access to view Tags');
        }

        if (request()->expectsJson()) {
            $tags = Tag::whereNull('parent_tag_id')->with(['tags.parentTag'])->get();
            return response()->json([
                'tags' => $tags,
            ]);
        }

        auth()->user()->enableEditing();
        return view('tags.index');
    }

    public function search()
    {
        if (!auth()->user()->can('viewAny', Tag::class)) {
            return response()->json(['error' => 'You do not have permission to view tags'], 403);
        }

        request()->validate([
            'terms' => 'required',
        ]);

        //$tags = Tag::where('name', 'LIKE', '%'.Str::title(request('terms')).'%')->get();
        $tags = (new Tag())->search(request('terms'), true);

        if (request('parents')) {
            $tags = $tags->filter(function ($tag) {
                return $tag->parent_tag_id ? false : true;
            });
        } else {
            if ($tags->count()) {
                $childern = $tags->map->tags->flatten();
                if ($childern->count()) {
                    $tags = $tags->merge($childern)->unique();
                }
            }
        }

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

    public function store(TagValidation $request, $id = null)
    {
        if ($id) {
            $tag = Tag::findOrFail($id);
            if (!auth()->user()->can('update', $tag)) {
                return response()->json(['error' => 'You do not have permission to update that Tag'], 403);
            }
        } else {
            if (!auth()->user()->can('create', Tag::class)) {
                return response()->json(['error' => 'You do not have permission to create Tags'], 403);
            }
        }

        $tag = (new Tag())->saveTag(requestInput(), $id);

        return response()->json([
            'success' => $tag->name.' Saved',
            'tag' => $tag,
        ]);
    }

    public function items($id)
    {
        if (!auth()->user()->can('viewAny', Tag::class)) {
            return response()->json(['error' => 'You do not have permission to view tags'], 403);
        }

        $items = Tag::where('id', $id)->with(['items.taggable' => function (MorphTo $morphTo) {
            $morphTo->morphWith([
                Announcement::class => ['version'],
                Blog::class => ['version'],
                Course::class => ['version'],
                Page::class => ['version'],
                ContentElement::class => ['contentables.pageable'],
            ]);
        }])
            ->first()
            ->items->filter(function ($item) {
                return $item->taggable ? true : false;
            })
            ->map(function ($item) {
                $taggable = $item->taggable;
                $slugs = collect();

                if (collect(class_uses($taggable))->contains('App\Traits\SlugTrait')) {
                    $slugs->push($taggable->append(['full_slug', 'name']));
                }

                if ($taggable instanceof ContentElement) {
                    $taggable->contentables->each(function ($contentable) use ($slugs) {
                        if ($contentable->pageable?->full_slug) {
                            $slugs->push($contentable->pageable->append(['full_slug']));
                        }
                    });
                }

                if (collect(class_uses($taggable))->contains('App\Traits\ContentElementTrait')) {
                    if ($taggable->contentElement) {
                        $taggable->contentElement->contentables->each(function ($contentable) use ($slugs) {
                            if ($contentable->pageable?->full_slug) {
                                $slugs->push($contentable->pageable->append(['full_slug']));
                            }
                        });
                    }
                }

                if ($taggable instanceof Livestream) {
                    $slugs->push($taggable->append(['full_slug']));
                }

                if ($taggable instanceof StaffProfile) {
                    $taggable->full_slug = 'staff-profiles/'.$taggable->id.'/edit';
                    $slugs->push($taggable->append(['name']));
                }

                return [
                    'taggable' => $taggable,
                    'taggable_id' => $item->taggable_id,
                    'taggable_type' => $item->taggable_type,
                    'slugs' => $slugs,
                ];
            });

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

    public function removeItems($id)
    {
        $tag = Tag::findOrFail($id);

        if (!auth()->user()->can('update', $tag)) {
            return response()->json(['error' => 'You do not have permission to update tags'], 403);
        }

        $input = request()->all();

        Validator::make($input, [
            'items' => 'required|array',
            'items.*.taggable_id' => 'required|integer',
            'items.*.taggable_type' => 'required',
        ])->validate();

        $items = collect(Arr::get($input, 'items'))
            ->map(function ($data) {
                $classname = Arr::get($data, 'taggable_type');
                return (new $classname())->findOrFail(Arr::get($data, 'taggable_id'));
            });

        foreach ($items as $item) {
            $item->tags()->detach($tag->id);
        }

        return response()->json([
            'success' => $items->count().' Items Removed',
        ]);
    }

    public function retagItems($id)
    {
        $tag = Tag::findOrFail($id);

        if (!auth()->user()->can('update', $tag)) {
            return response()->json(['error' => 'You do not have permission to update tags'], 403);
        }

        $input = request()->all();

        Validator::make($input, [
            'items' => 'required|array',
            'items.*.taggable_id' => 'required|integer',
            'items.*.taggable_type' => 'required',
            'new_tag_id' => 'required|exists:tags,id',
        ])->validate();

        $new_tag = Tag::findOrFail(Arr::get($input, 'new_tag_id'));

        $items = collect(Arr::get($input, 'items'))
            ->map(function ($data) {
                $classname = Arr::get($data, 'taggable_type');
                return (new $classname())->findOrFail(Arr::get($data, 'taggable_id'));
            });

        foreach ($items as $item) {
            $item->tags()->detach($tag->id);
            $item->addTag($new_tag);
        }

        return response()->json([
            'success' => $items->count().' Items Retagged',
        ]);
    }
}
