<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Requests\Comment\StoreCommentRequest;
use App\Http\Requests\Comment\UpdateCommentRequest;
use App\Http\Resources\CommentResource;
use App\Models\Comment;
use App\Support\ApiResponse;
use App\Support\MorphTypeResolver;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use InvalidArgumentException;

class CommentController extends Controller
{
  public function index(Request $request)
  {
    Gate::authorize('viewAny', Comment::class);

    if (! $request->filled('commentable_type') || ! $request->filled('commentable_id')) {
      return ApiResponse::response(message: 'commentable_type و commentable_id الزامی هستند.', status: 422);
    }

    try {
      $commentableType = MorphTypeResolver::resolve($request->string('commentable_type'));
    } catch (InvalidArgumentException $exception) {
      return ApiResponse::response(message: $exception->getMessage(), status: 422);
    }

    $query = Comment::query()
      ->with([
        'user',
        'replies' => function ($replies) use ($request): void {
          $replies->with('user')->latest();

          if (! $request->user()?->hasRole('admin')) {
            $replies->where('status', Comment::STATUS_APPROVED);
          }
        },
      ])
      ->where('commentable_type', $commentableType)
      ->where('commentable_id', $request->integer('commentable_id'))
      ->whereNull('parent_id')
      ->latest();

    if (! $request->user()?->hasRole('admin')) {
      $query->where('status', Comment::STATUS_APPROVED);
    } elseif ($request->filled('status')) {
      $query->where('status', $request->string('status'));
    }

    if ($request->filled('category')) {
      $query->where('category', $request->string('category'));
    }

    $perPage = min($request->integer('per_page', 15), 50);

    return CommentResource::collection(
      $request->boolean('noPaginate') ? $query->get() : $query->paginate($perPage)
    );
  }

  public function store(StoreCommentRequest $request)
  {
    Gate::authorize('create', Comment::class);

    try {
      $commentableType = MorphTypeResolver::resolve($request->string('commentable_type'));
      $commentableId = $request->integer('commentable_id');

      $commentableClass = $commentableType;
      $commentableClass::query()->findOrFail($commentableId);

      DB::beginTransaction();

      $comment = Comment::create([
        'user_id' => Auth::id(),
        'commentable_type' => $commentableType,
        'commentable_id' => $commentableId,
        'parent_id' => $request->input('parent_id'),
        'body' => $request->string('body'),
        'category' => $request->input('category'),
        'status' => Comment::STATUS_APPROVED,
      ]);

      DB::commit();
    } catch (InvalidArgumentException $exception) {
      return ApiResponse::response(message: $exception->getMessage(), status: 422);
    } catch (Exception $exception) {
      DB::rollBack();

      return ApiResponse::response(message: $exception->getMessage(), status: 419);
    }

    return ApiResponse::created(
      new CommentResource($comment->load(['user', 'replies.user'])),
      'نظر با موفقیت ثبت شد.'
    );
  }

  public function show(Comment $comment)
  {
    Gate::authorize('view', $comment);

    return new CommentResource($comment->load(['user', 'replies.user']));
  }

  public function update(UpdateCommentRequest $request, Comment $comment)
  {
    Gate::authorize('update', $comment);

    try {
      DB::beginTransaction();
      $comment->update($request->validated());
      DB::commit();
    } catch (Exception $exception) {
      DB::rollBack();

      return ApiResponse::response(message: $exception->getMessage(), status: 419);
    }

    return new CommentResource($comment->fresh()->load(['user', 'replies.user']));
  }

  public function destroy(Comment $comment)
  {
    Gate::authorize('delete', $comment);

    try {
      DB::beginTransaction();
      $comment->delete();
      DB::commit();
    } catch (Exception $exception) {
      DB::rollBack();

      return ApiResponse::response(message: $exception->getMessage(), status: 419);
    }

    return ApiResponse::success(message: 'با موفقیت حذف شد');
  }
}
