<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests\ContentElementValidation;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Validator;
use Tiptap\Editor;

use App\Models\ContentElement;
use App\Models\Page;
use App\Events\ContentElementRemoved;
use App\Http\Requests\ContentElementPublishValidation;
use App\Models\Contentable;

class ContentElementsController extends Controller
{
    protected function getModel()
    {
        return new ContentElement();
    }

    /**
     * Find the page associated with the requested URL path
     * This is the main function to render all content pages
     */
    public function load($id)
    {
        Validator::make(request()->all(), [
            'pivot.contentable_id' => 'required|integer',
            'pivot.contentable_type' => 'required|string',
        ])->validate();

        $content_element = ContentElement::findOrFail($id);

        $contentable = ContentElement::findContentable(requestInput());
        $content_element = $contentable->contentElements()
                                       ->where('uuid', $content_element->uuid)
                                        ->orderByDesc('content_elements.id')
                                        ->with((new ContentElement())->loadWith())
                                        ->first()
                                        ->append((new ContentElement())->appendWith());

        if (!auth()->user()->can('view', $content_element)) {
            if (request()->expectsJson()) {
                return response()->json(['error' => 'You do not have permission to load that item'], 403);
            }
            return redirect('/')->with(['error' => 'You do not have permission to load that item']);
        }

        $content_element->content->appendAttributes();

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

    public function store(ContentElementValidation $request, $id = null)
    {
        $contentable = ContentElement::findContentable(requestInput());
        $content_element = (new ContentElement())->saveContentElement(requestInput(), $id);
        // TODO somehow a user was able to hit this and not find a content element
        $content_element = $contentable->contentElements()
                                       ->where('content_element_id', $content_element->id)
                                       ->first();
        if ($content_element) {
            $content_element->load((new ContentElement())->loadWith())
                ->append((new ContentElement())->appendWith());
            $content_element->content->appendAttributes();
        }

        return response()->json([
            'success' => Str::title(str_replace('-', ' ', $content_element?->type)).' Saved',
            'content_element' => $content_element,
        ]);
    }

    public function remove($id)
    {
        Validator::make(request()->all(), [
            'pivot.contentable_id' => 'required|integer',
            'pivot.contentable_type' => 'required|string',
        ])->validate();

        $content_element = ContentElement::findOrFail($id)->load('contentables');

        if (!auth()->check()) {
            return abort(401);
        }

        if (!auth()->user()->can('delete', $content_element)) {
            if (request()->expectsJson()) {
                return response()->json(['error' => 'You do not have permission to remove that item'], 403);
            }
            return redirect('/')->with(['error' => 'You do not have permission to remove that item']);
        }


        $page = ContentElement::findContentable(requestInput());

        $version = $content_element->getPageVersion($page);

        if ($version->published_at) {
            // create a new version so it can be published as well as maintain history
            $content_element = $content_element->createNewVersionOnPage($page);
        }

        $previous_content_element = $content_element->getPreviousVersion($page);

        if ($previous_content_element) {
            $previous_content_element = $page->contentElements()
                                           ->where('content_element_id', $previous_content_element->id)
                                           ->first()
                                           ->load((new ContentElement())->loadWith())
                                           ->append((new ContentElement())->appendWith());
        }

        $contentables = Contentable::where('content_element_id', $content_element->id)
                            ->where('contentable_id', $page->id)
                            ->where('contentable_type', get_class($page))
                            ->get();

        if ($contentables->count() > 1) {
            abort(404, 'There was more than one contentable found');
        }

        $contentable = $contentables->first();

        if (requestInput('remove_all')) {
            $contentable->deleted_at = now();
            $contentable->save();
        } else {
            // its just a draft so nuke it
            if (!$contentable->version->published_at) {
                $contentable->delete();
            } else {
                // we should never get here, all removals should be drafted
            }
        }

        // remove the content element if it doesn't belong to any other pages.
        if (!Contentable::where('content_element_id', $content_element->id)->count()) {
            $content_element->delete();
        }

        cache()->tags([cache_name($page)])->flush();
        cache()->tags([cache_name($content_element)])->flush();

        broadcast(new ContentElementRemoved($content_element, $page))->toOthers();

        return response()->json([
            'success' => Str::title(str_replace('-', ' ', $content_element->type)).' '.(requestInput('remove_all') ? 'Removed From Page' : 'Version Removed'),
            'content_element' => requestInput('remove_all') ? null : $previous_content_element,
        ]);
    }

    public function restore($id)
    {
        $content_element = ContentElement::onlyTrashed()
            ->where('id', $id)
            ->first();

        if (!auth()->check()) {
            return abort(401);
        }

        if (!auth()->user()->can('delete', $content_element)) {
            if (request()->expectsJson()) {
                return response()->json(['error' => 'You do not have permission to restore that item'], 403);
            }
            return redirect('/')->with(['error' => 'You do not have permission to restore that item']);
        }

        $content_element->restore();

        return response()->json(['success' => Str::title(str_replace('-', ' ', $content_element->type)).' Restored']);
    }

    public function publish(ContentElementPublishValidation $request, $id)
    {
        $contentable = ContentElement::findContentable(requestInput());
        $content_element = $contentable->contentElements()->where('content_element_id', $id)->first();

        $contentable->publishContentElement($content_element);

        return response()->json(['success' => Str::title(str_replace('-', ' ', $content_element->type)).' Published']);
    }

    public function loadField()
    {
        request()->validate([
            'id' => 'required|exists:content_elements',
            'field' => 'required|string',
        ]);

        $content_element = ContentElement::findOrFail(request('id'));

        if (!auth()->user()->can('update', $content_element)) {
            return response()->json(['error' => 'You do not have access to that content element'], 403);
        }

        $content_id = $content_element->content->id;
        $content_class = get_class($content_element->content);

        $content = (new $content_class())->find($content_id);

        $field = $content->getRawOriginal(request('field'));

        if (Str::length($field) < 1) {
            $field = '<p></p>';
        }

        return response()->json([
            'content' => (new Editor())->setContent($field)->getDocument(),
        ]);
    }

    public function previousVersion($id)
    {
        request()->validate([
            'contentable_id' => 'required|integer',
            'contentable_type' => 'required|string',
        ]);

        $content_element = ContentElement::findOrFail($id);

        if (!auth()->user()->can('update', $content_element)) {
            return response()->json(['error' => 'You do not have access to that content element'], 403);
        }

        $contentable = ContentElement::findContentable([
            'pivot' => [
                'contentable_id' => request('contentable_id'),
                'contentable_type' => request('contentable_type'),
            ],
        ]);

        $previous_version_id = optional($content_element->getPreviousVersion($contentable))->id;

        if ($previous_version_id) {
            $previous_version = $contentable->contentElements()->where('content_element_id', $previous_version_id)->first();
            $previous_version->load((new ContentElement())->loadWith());
            $previous_version->append((new ContentElement())->appendWith());
        } else {
            $previous_version = null;
        }

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