<?php

namespace App\Http\Controllers\Board;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\CommentRequest;
use App\Http\Traits\PagingTrait;
use App\Services\BoardService;
use App\Services\PostService;
use App\Services\CommentService;
use App\Models\Board;
use App\Models\BoardMeta;
use App\Models\Comment;
use App\Models\DTO\SearchData;
use App\Models\DTO\ResponseData;

class CommentController extends Controller
{
    use PagingTrait;

    protected BoardService $boardService;
    protected PostService $postService;
    protected CommentService $commentService;

    protected string $code; // 게시판 코드
    protected int $postID; // 게시글 번호
    protected Board $board; // 게시판 정보
    protected BoardMeta $boardMeta; // 게시판 설정 값
    protected ?Comment $comment; // 게시판 설정 값

    public function __construct(
        BoardService $boardService,
        PostService $postService,
        CommentService $commentService
    ) {
        $this->middleware(['front', 'authed']);

        // 인증 필수
        $this->middleware('auth')->only([
            'blame', 'like', 'dislike'
        ]);

        // 댓글 읽기 권한 확인
        $this->middleware('comment.access')->only('index');

        // 댓글 쓰기 권한 확인
        $this->middleware('comment.create')->only(['store', 'reply']);

        // 댓글 수정 권한 확인
        $this->middleware('comment.update')->only('update');

        // 댓글 삭제 권한 확인
        $this->middleware('comment.delete')->only('delete');

        // 댓글/답글 속도 제한
        $this->middleware('throttle:commentWrite')->only(['store', 'reply']);

        $this->boardService = $boardService;
        $this->postService = $postService;
        $this->commentService = $commentService;
    }

    /**
     * 댓글 목록
     * @method GET
     * @see /board/{code}/{postID}/comment
     */
    public function index(Request $request, string $code, int $postID)
    {
        $params = SearchData::fromRequest($request);
        $this->board = $request->board;
        $this->boardMeta = $request->boardMeta;

        if($perPage = $this->boardMeta->item('comment_per_page', 0)) {
            $params->perPage = intval($perPage);
            $params->offset = $this->getPageOffset($params->page, $params->perPage);
        }

        if($pageCount = $this->boardMeta->item('comment_page_count', 0)) {
            $params->pageCount = intval($pageCount);
        }

        $params->sort = intval($request->query('sort', 1)); // 정렬 (최신순, 공감순, 댓글순)

        $comment = $this->commentService->list($code, $postID, $params);

        return view(layout('board.comment.index'), [
            'boardMeta' => $this->boardMeta,
            'comment' => $comment,
            'params' => $params
        ]);
    }

    /**
     * 댓글 등록
     * @method POST
     * @see /board/{code}/{postID}/comment/store
     */
    public function store(CommentRequest $request, ResponseData $response, string $code): ResponseData
    {
        $this->board = $request->board;
        $this->boardMeta = $request->boardMeta;

        // 댓글 등록
        $result = $this->commentService->register($request, $response);

        if(!$result->success) {
            return $result;
        }

        $this->comment = $result->comment;

        // 댓글 작성 경험치 처리
        $this->commentService->setUserExp($this->comment, $this->comment->user, EXP_TYPE_8);

        // 최근 게시글 캐시 삭제
        $this->boardService->clearLatest($code);

        $result->cid = $this->comment->id;

        // 이메일 발송
        $this->commentService->sendEmailNotify($this->comment, (
        	$this->boardMeta->item('use_personal', 0) ? SEND_MAIL_FORM_TYPE_12 : SEND_MAIL_FORM_TYPE_8
        ));

        unset($result->comment, $this->comment);

        return $result;
    }

    /**
     * 댓글 수정
     * @method PUT
     * @see /board/{code}/{postID}/comment/update
     */
    public function update(CommentRequest $request, ResponseData $response): ResponseData
    {
        // 댓글 수정
        $result = $this->commentService->updater($request, $response);

        if(!$result->success) {
            return $result;
        }

        $result->cid = $request->comment->id;

        unset($result->comment);

        return $result;
    }

    /**
     * 댓글 답글
     * @method POST
     * @see /board/{code}/{postID}/comment/reply
     */
    public function reply(CommentRequest $request, ResponseData $response, string $code): ResponseData
    {
        $this->board = $request->board;
        $this->boardMeta = $request->boardMeta;

        // 댓글 답글
        $result = $this->commentService->reply($request, $response);

        if(!$result->success) {
            return $result;
        }

        $this->comment = $result->comment;

        // 댓글 작성 경험치 처리
        $this->commentService->setUserExp($this->comment, $this->comment->user, EXP_TYPE_8);

        // 최근 게시글 캐시 삭제
        $this->boardService->clearLatest($code);

        $result->cid = $this->comment->id;

        // 이메일 발송
        $this->commentService->sendEmailNotify($this->comment, (
        	$this->boardMeta->item('use_personal', 0) ? SEND_MAIL_FORM_TYPE_12 : SEND_MAIL_FORM_TYPE_8
        ));

        unset($result->comment, $this->comment);

        return $result;
    }

    /**
     * 댓글 삭제
     * @method DELETE
     * @see /board/{code}/{postID}/comment/delete
     */
    public function delete(Request $request, ResponseData $response, string $code): ResponseData
    {
        $request->validate([
            'bid' => 'required|numeric|exists:tb_board,id',
            'pid' => 'required|numeric|exists:tb_post,id',
            'cid' => 'required|numeric|exists:tb_comment,id'
        ]);

        $result = $this->commentService->delete($request, $response);

        if(!$result->success) {
            return $result;
        }

        $this->comment = $request->comment;

        // 관리자인 경우
        if(IS_ADMIN) {
            $expType = EXP_TYPE_11;
        }else{
            $expType = EXP_TYPE_12;
        }

        // 댓글 삭제 경험치 처리
        $this->commentService->setUserExp($this->comment, $this->comment->user, $expType);

        // 최근 게시글 캐시 삭제
        $this->boardService->clearLatest($code);

        unset($result->comment, $this->comment);

        return $result;
    }

    /**
     * 댓글 신고
     * @method POST
     * @see /board/{code}/{postID}/comment/blame
     */
    public function blame(Request $request, ResponseData $response): ResponseData
    {
        $request->validate([
            'bid' => 'required|numeric|exists:tb_board,id',
            'pid' => 'required|numeric|exists:tb_post,id',
            'cid' => 'required|numeric|exists:tb_comment,id',
            'type' => 'required|numeric|in:1,2,3,4,5,6,7,8,9',
            'reason' => 'nullable|string|max:1000'
        ]);

        $result = $this->commentService->blame($request, $response);

        if(!$result->success) {
            return $result;
        }

        $this->comment = $result->comment;

        // 이메일 발송
        $this->commentService->sendEmailNotify($this->comment, SEND_MAIL_FORM_TYPE_10);

        unset($result->comment, $this->comment);

        return $result;
    }

    /**
     * 댓글 좋아요
     * @method POST
     * @see /board/{code}/{postID}/comment/like
     */
    public function like(Request $request, ResponseData $response): ResponseData
    {
        $request->validate([
            'bid' => 'required|numeric|exists:tb_board,id',
            'pid' => 'required|numeric|exists:tb_post,id',
            'cid' => 'required|numeric|exists:tb_comment,id'
        ]);

        $result = $this->commentService->like($request, $response);

        if(!$result->success) {
            return $result;
        }

        $this->comment = $result->comment;

        // 댓글 좋아요 경험치 처리
        $this->commentService->setUserExp($this->comment, $request->user(), EXP_TYPE_21);

        // 댓글 좋아요 받음 (상대방)
        $this->commentService->setUserExp($this->comment, $this->comment->user, EXP_TYPE_23);

        unset($result->comment, $this->comment);

        return $result;
    }

    /**
     * 댓글 싫어요
     * @method POST
     * @see /board/{code}/{postID}/comment/dislike
     */
    public function dislike(Request $request, ResponseData $response): ResponseData
    {
        $request->validate([
            'bid' => 'required|numeric|exists:tb_board,id',
            'pid' => 'required|numeric|exists:tb_post,id',
            'cid' => 'required|numeric|exists:tb_comment,id'
        ]);

        $result = $this->commentService->dislike($request, $response);

        if(!$result->success) {
            return $result;
        }

        $this->comment = $result->comment;

        // 댓글 싫어요 경험치 처리
        $this->commentService->setUserExp($this->comment, $request->user(), EXP_TYPE_22);

        // 댓글 싫어요 받음 (상대방)
        $this->commentService->setUserExp($this->comment, $this->comment->user, EXP_TYPE_24);

        unset($result->comment, $this->comment);

        return $result;
    }
}
