<?php

namespace App\Http\Controllers\Board;

use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use App\Http\Requests\PostRequest;
use App\Services\BoardService;
use App\Services\PostService;
use App\Models\Board;
use App\Models\Post;
use App\Models\BoardMeta;
use App\Models\DTO\ResponseData;

class PostController extends Controller
{
    protected BoardService $boardService;
    protected PostService $postService;

    protected string $code; // 게시판 코드
    protected Board $board; // 게시판 정보
    protected BoardMeta $boardMeta; // 게시판 설정 값
    protected ?Post $post;

    public function __construct(
        BoardService $boardService,
        PostService $postService
    ) {
        $this->middleware('authed');
        $this->middleware('front')->only(['view', 'write', 'edit', 'uploader']);

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

        // 게시글 보기 권한 확인
        $this->middleware('post.access')->only('view');

        // 게시글 쓰기 권한 확인
        $this->middleware('post.create')->only(['write', 'store']);

        // 게시글 수정 권한 확인
        $this->middleware('post.update')->only(['edit', 'update']);

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

        // 게시글 이미치 첨부 권한 확인
        $this->middleware('post.uploader')->only('uploader');

        // 게시글 파일 다운로드 권한 확인
        $this->middleware('post.download')->only('download');

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

    /**
     * 게시글 보기
     * @method GET
     * @see /board/{code}/{postID}
     */
    public function view(Request $request, string $code, int $postID)
    {
        $this->board = $request->board;
        $this->boardMeta = $request->boardMeta;
        $this->post = $request->post;

        // 댓글 위치 ID
        $id = $request->get('id', 0);

        if(DEVICE_TYPE_1) {
            $perPage = $request->get('per_page', $this->boardMeta->item('list_per_page', DEFAULT_LIST_PER_PAGE));
            $pageCount = $this->boardMeta->item('list_page_count', DEFAULT_LIST_PAGE_COUNT);
        }else{
            $perPage = $request->get('per_page', $this->boardMeta->item('list_mobile_per_page',DEFAULT_LIST_PER_PAGE));
            $pageCount = $this->boardMeta->item('list_page_mobile_count', DEFAULT_LIST_PAGE_COUNT);
        }

        $page = $request->get('page', $this->post->findPageNumber($postID));

        $latest = $this->boardService->latest($code, $page, $perPage);

        // 게시글 읽기 경험치 처리
        $this->postService->setUserExp($this->post, $this->post->user, EXP_TYPE_16);

        return view(layout('board.view'), [
            'board' => $this->board,
            'boardMeta' => $this->boardMeta,
            'post' => $this->post,
            'latest' => $latest, // 최근 게시글
            'id' => $id, // 댓글 PK
            'page' => $page, // 댓글 위치 페이지
            'pageCount' => $pageCount,
            'listURL' => route('board.list', $code),
            'editURL' => route('board.post.edit', [$code, $postID]),
            'deleteURL' => route('board.post.delete', [$code, $postID])
        ]);
    }

    /**
     * 게시글 작성
     * @method GET
     * @see /board/{code}/write
     */
    public function write(Request $request, string $code)
    {
        $this->board = $request->board;
        $this->boardMeta = $request->boardMeta;

        $category = $this->boardService->categories(
            $this->board->getKey()
        );

        return view(layout('board.write'), [
            'board' => $this->board,
            'boardMeta' => $this->boardMeta,
            'category' => $category,
            'post' => null,
            'listURL' => route('board.list', $code),
            'storeURL' => route('board.post.store', $code),
            'provisionURL' => route('document', 'provision'),
            'boardRuleURL' => route('document', 'rule01')
        ]);
    }

    /**
     * 게시글 수정
     * @method GET
     * @see /board/{code}/{postID}/edit
     */
    public function edit(Request $request, string $code, int $postID)
    {
        $this->board = $request->board;
        $this->boardMeta = $request->boardMeta;
        $this->post = $request->post;

        $category = $this->boardService->categories(
            $this->board->getKey()
        );

        return view(layout('board.edit'), [
            'board' => $this->board,
            'boardMeta' => $this->boardMeta,
            'category' => $category,
            'post' => $this->post,
            'listURL' => route('board.post.view', [$code, $postID]),
            'updateURL' => route('board.post.update', [$code, $postID]),
            'provisionURL' => route('document', 'provision'),
            'boardRuleURL' => route('document', 'rule01')
        ]);
    }

    /**
     * 게시글 저장
     * @method POST
     * @see /board/{code}
     */
    public function store(PostRequest $request, ResponseData $response, string $code)
    {
        $this->board = $request->board;
        $this->boardMeta = $request->boardMeta;

        // 게시글 등록
        $result = $this->postService->register($request, $response);

        if(!$result->success) {
            return back()->with('message', $result->message)->withInput();
        }

        $this->post = $result->post;

        // 게시글 작성 경험치 처리
        $this->postService->setUserExp($this->post, $this->post->user,EXP_TYPE_7);

        // 파일 업로드 시 경험치 처리
        if($this->post->file_rows > 0) {
            $this->postService->setUserExp($this->post, $this->post->user,EXP_TYPE_13);
        }

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

        // 이메일 발송
        $this->postService->sendEmailNotify($this->post, (
        	$this->boardMeta->item('use_personal', 0) ? SEND_MAIL_FORM_TYPE_11 : SEND_MAIL_FORM_TYPE_7
        ));

        return redirect()->route('board.post.view', [
            $code, $this->post
        ]);
    }

    /**
     * 게시글 수정 처리
     * @method PUT
     * @see /board/{code}/{postID}
     */
    public function update(PostRequest $request, ResponseData $response, string $code, int $postID)
    {
        // 게시글 수정
        $result = $this->postService->updater($request, $response);

        if(!$result->success) {
            return back()->with('message', $result->message)->withInput();
        }

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

        return redirect()->route('board.post.view', [
            $code, $postID
        ]);
    }

    /**
     * 게시글 삭제
     * @method DELETE
     * @see /board/{code}/{postID}
     */
    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',
        ]);

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

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

        $this->post = $request->post;

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

        // 게시글 삭제 경험치 처리
        $this->postService->setUserExp($this->post, $this->post->user, $expType);

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

        return $result;
    }

    /**
     * 게시글 즐겨찾기
     * @method POST
     * @see /board/{code}/{postID}/bookmark
     */
    public function bookmark(Request $request, ResponseData $response): ResponseData
    {
        $request->validate([
            'bid' => 'required|numeric|exists:tb_board,id',
            'pid' => 'required|numeric|exists:tb_post,id'
        ]);

        $result = $this->postService->bookmark($request, $response);

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

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

        return $result;
    }

    /**
     * 게시글 신고
     * @method POST
     * @see /board/{code}/{postID}/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',
            'type' => 'required|numeric|in:1,2,3,4,5,6,7,8,9',
            'reason' => 'nullable|string|max:1000'
        ]);

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

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

        $this->post = $result->post;

        // 이메일 발송
        $this->postService->sendEmailNotify($this->post, SEND_MAIL_FORM_TYPE_9);

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

        return $result;
    }

    /**
     * 게시글 좋아요
     * @method POST
     * @see /board/{code}/{postID}/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',
            'type' => 'required|numeric|in:1,2'
        ]);

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

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

        $post = $result->post;

        // 게시글 좋아요 경험치 처리
        $this->postService->setUserExp($post, $request->user(), EXP_TYPE_17);

        // 게시글 좋아요 받음 (상대방)
        $this->postService->setUserExp($post, $post->user, EXP_TYPE_19);

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

        return $result;
    }

    /**
     * 게시글 싫어요
     * @method POST
     * @see /board/{code}/{postID}/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',
            'type' => 'required|numeric|in:1,2'
        ]);

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

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

        $post = $result->post;

        // 게시글 싫어요 경험치 처리
        $this->postService->setUserExp($post, $request->user(), EXP_TYPE_18);

        // 게시글 싫어요 받음 (상대방)
        $this->postService->setUserExp($post, $post->user, EXP_TYPE_20);

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

        return $result;
    }

    /**
     * 게시글 첨부파일 다운로드
     * @method POST
     * @see /board/{code}/{postID}/download
     */
    public function download(Request $request)
    {
        $posts = $request->validate([
            'bid' => 'required|numeric|exists:tb_board,id',
            'pid' => 'required|numeric|exists:tb_post,id',
            'fid' => 'required|numeric|exists:tb_post_file,id'
        ]);

        $fileInfo = $this->postService->download($request);
        if(!file_exists($fileInfo->path)) {
            return back()->with('message', '해당 파일이 존재하지 않습니다.');
        }

        $post = $this->postService->postModel->findOrNew($posts['pid']);

        // 게시글 다운로드 경험치 처리
        $this->postService->setUserExp($post, $request->user(), EXP_TYPE_14);

        // 게시글 파일 다운로드 시 (상대방)
        $this->postService->setUserExp($post, $post->user, EXP_TYPE_15);

        return response()->download($fileInfo->path, $fileInfo->name);
    }

    /**
     * 게시글 Link 클릭
     * @method POST
     * @see /board/{code}/{postID}/link
     */
    public function link(Request $request): JsonResponse
    {
        $request->validate([
            'bid' => 'required|numeric|exists:tb_board,id',
            'pid' => 'required|numeric|exists:tb_post,id',
            'lid' => 'required|numeric|exists:tb_post_link,id'
        ]);

        $href = $this->postService->linked($request);

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

    /**
     * 게시글 이미지 첨부
     * @method GET
     * @see /board/{code}/uploader
     */
    public function uploader()
    {
        return view('component.uploader');
    }
}
