<?php

namespace LaraBB\Thread\Actions;

use Illuminate\Database\Connection;
use LaraBB\Forum\Tasks\Forum\UpdateTask as UpdateForumTask;
use App\Traits\PivotData;
use Illuminate\Support\Str;
use LaraBB\Forum\Models\Forum;
use LaraBB\Post\Models\Post;
use LaraBB\Post\Tasks\StoreTask as StorePostTask;
use LaraBB\Thread\Models\Thread;
use LaraBB\Thread\Tasks\DestroyTask as DestroyThreadTask;
use LaraBB\Thread\Tasks\FindTask as FindThreadTask;
use LaraBB\Thread\Tasks\StoreTask as StoreThreadTask;
use LaraBB\Thread\Tasks\UpdateTask as UpdateThreadTask;
use LaraBB\Thread\UI\Web\Requests\Store;
use Throwable;

/**
 * Class StoreAction
 * @package LaraBB\Thread\Actions
 */
class StoreAction
{
    use PivotData;

    /**
     * @var Thread|null
     */
    private ?Thread $thread;

    /**
     * StoreAction constructor.
     * @param FindThreadTask $getThreadTask
     * @param UpdateForumTask $updateForumTask
     * @param UpdateThreadTask $updateThreadTask
     * @param StoreThreadTask $storeThreadTask
     * @param StorePostTask $storePostTask
     * @param DestroyThreadTask $destroyThreadTask
     * @param Connection $connection
     */
    public function __construct(
        private readonly FindThreadTask $getThreadTask,
        private readonly UpdateForumTask $updateForumTask,
        private readonly UpdateThreadTask $updateThreadTask,
        private readonly StoreThreadTask $storeThreadTask,
        private readonly StorePostTask $storePostTask,
        private readonly DestroyThreadTask $destroyThreadTask,
        private readonly Connection $connection
    ) {

    }

    /**
     * @param Store $request
     * @return false|Thread|null
     */
    public function run(Store $request): bool|Thread|null
    {
        try {
            $this->connection->transaction(function() use($request) {
                $this->thread = $this->storeThreadTask->run($this->prepareThreadData($request));
                if(is_null($this->thread)) {
                    throw new Exception('The thread could not be created');
                }

                $post = $this->storePostTask->run($this->preparePostData($this->thread, $request));
                $this->updateThreadTask->run($this->thread, [
                    'slug'           => $this->thread->slug . '-' . $this->thread->id,
                    'lastpost_uuid'  => $post->uuid,
                    'firstpost_uuid' => $post->uuid
                ]);

                $this->updateForumTask->run($request->forum, $this->prepareForumData($request->forum, $post));
            });
        } catch (Throwable $t) {
            return false;
        }

        return $this->thread;
    }

    /**
     * @param Store $request
     * @return array
     */
    private function prepareThreadData(Store $request): array
    {
        return [
            'created_uuid' => $request->user()->uuid,
            'updated_uuid' => $request->user()->uuid,
            'forum_uuid'   => $request->post('forum_uuid'),
            'prefix_uuid'  => $request->post('prefix'),
            'title'        => $request->post('title'),
            'slug'         => Str::slug($request->post('title')),
            'users'        => $this->preparePivotData($request, 'users'),
            'groups'       => $this->preparePivotData($request, 'groups'),
        ];
    }

    /**
     * @param Thread $thread
     * @param Store $request
     * @return array
     */
    private function preparePostData(Thread $thread, Store $request): array
    {
        return [
            'created_uuid' => $request->user()->uuid,
            'updated_uuid' => $request->user()->uuid,
            'thread_uuid'  => $thread->uuid,
            'title'        => $request->post('title'),
            'content'      => $request->post('content'),
            'users'        => $this->preparePivotData($request, 'users'),
            'groups'       => $this->preparePivotData($request, 'groups'),
        ];
    }

    /**
     * @param Forum $forum
     * @param Post $post
     * @return array
     */
    private function prepareForumData(Forum $forum, Post $post): array
    {
        return [
            'thread_count'  => $forum->thread_count + 1,
            'posting_count' => $forum->posting_count + 1,
            'lastpost_uuid' => $post->uuid
        ];
    }
}
