<?php

namespace App\Services;

use App\Models\Boards\Board;
use App\Models\Boards\BoardComment;
use App\Models\Boards\File;
use App\Models\Boards\Post;
use App\Models\Boards\PostCustomFieldValue;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class PostService
{
    /**
     * 게시글 목록 조회 (페이지네이션)
     *
     * @param  bool  $includeTrashed  슈퍼관리자용: 삭제된 게시물 포함
     */
    public function getPosts(int $boardId, array $filters = [], int $perPage = 15, bool $includeTrashed = false): LengthAwarePaginator
    {
        $query = Post::query()
            ->ofBoard($boardId)
            ->with(['author', 'board'])
            ->withCount(['files', 'comments'])
            ->published();

        // 슈퍼관리자: 삭제된 게시물 포함
        if ($includeTrashed) {
            $query->withTrashed();
        }

        // 검색
        if (! empty($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('title', 'like', "%{$search}%")
                    ->orWhere('content', 'like', "%{$search}%");
            });
        }

        // 공지사항 필터
        if (isset($filters['is_notice'])) {
            $query->where('is_notice', $filters['is_notice']);
        }

        // 삭제 상태 필터
        if (isset($filters['trashed'])) {
            if ($filters['trashed'] === 'only') {
                $query->onlyTrashed();
            } elseif ($filters['trashed'] === 'with') {
                $query->withTrashed();
            }
        }

        // 정렬: 공지사항 먼저, 그 다음 최신순
        $query->orderByDesc('is_notice')
            ->orderByDesc('created_at');

        return $query->paginate($perPage);
    }

    /**
     * 공지사항 목록 (상단 고정용)
     */
    public function getNotices(int $boardId, int $limit = 5): Collection
    {
        return Post::query()
            ->ofBoard($boardId)
            ->published()
            ->notices()
            ->with('author')
            ->orderByDesc('created_at')
            ->limit($limit)
            ->get();
    }

    /**
     * 게시글 상세 조회
     */
    public function getPostById(int $id, bool $withTrashed = false): ?Post
    {
        $query = Post::query()
            ->with(['board.fields', 'author', 'customFieldValues.field']);

        if ($withTrashed) {
            $query->withTrashed();
        }

        return $query->find($id);
    }

    /**
     * 게시글 생성
     */
    public function createPost(Board $board, array $data, array $customFields = []): Post
    {
        return DB::transaction(function () use ($board, $data, $customFields) {
            // 기본 데이터 설정
            $data['board_id'] = $board->id;
            // 시스템 게시판(tenant_id=null)인 경우 사용자의 현재 테넌트 사용
            $data['tenant_id'] = $board->tenant_id ?? auth()->user()->currentTenant()?->id;
            $data['user_id'] = auth()->id();
            $data['created_by'] = auth()->id();
            $data['editor_type'] = $board->editor_type;
            $data['ip_address'] = request()->ip();

            $post = Post::create($data);

            // 커스텀 필드 저장
            $this->saveCustomFields($post, $board, $customFields);

            return $post->load(['board', 'author', 'customFieldValues.field']);
        });
    }

    /**
     * 게시글 수정
     */
    public function updatePost(Post $post, array $data, array $customFields = []): Post
    {
        return DB::transaction(function () use ($post, $data, $customFields) {
            $data['updated_by'] = auth()->id();

            $post->update($data);

            // 커스텀 필드 업데이트
            $this->saveCustomFields($post, $post->board, $customFields);

            return $post->fresh(['board', 'author', 'customFieldValues.field']);
        });
    }

    /**
     * 게시글 삭제 (Soft Delete)
     */
    public function deletePost(Post $post): bool
    {
        $post->deleted_by = auth()->id();
        $post->save();

        return $post->delete();
    }

    /**
     * 게시글 영구 삭제
     */
    public function forceDeletePost(Post $post): bool
    {
        // 첨부파일 영구 삭제
        $this->forceDeleteAllFiles($post);

        // 커스텀 필드 값 삭제
        $post->customFieldValues()->delete();

        return $post->forceDelete();
    }

    /**
     * 게시글 복원
     */
    public function restorePost(Post $post): bool
    {
        $post->deleted_by = null;

        return $post->restore();
    }

    /**
     * 조회수 증가
     */
    public function incrementViews(Post $post): void
    {
        $post->incrementViews();
    }

    /**
     * 커스텀 필드 저장
     */
    private function saveCustomFields(Post $post, Board $board, array $customFields): void
    {
        // 기존 값 삭제 후 새로 저장 (upsert 대신 간단한 방식)
        $post->customFieldValues()->delete();

        $boardFields = $board->fields;

        foreach ($boardFields as $field) {
            $value = $customFields[$field->field_key] ?? null;

            if ($value !== null && $value !== '') {
                PostCustomFieldValue::create([
                    'post_id' => $post->id,
                    'field_id' => $field->id,
                    'value' => is_array($value) ? json_encode($value) : $value,
                    'created_by' => auth()->id(),
                ]);
            }
        }
    }

    /**
     * 이전/다음 글 조회
     */
    public function getAdjacentPosts(Post $post): array
    {
        $prev = Post::query()
            ->ofBoard($post->board_id)
            ->published()
            ->where('id', '<', $post->id)
            ->orderByDesc('id')
            ->first(['id', 'title']);

        $next = Post::query()
            ->ofBoard($post->board_id)
            ->published()
            ->where('id', '>', $post->id)
            ->orderBy('id')
            ->first(['id', 'title']);

        return compact('prev', 'next');
    }

    /**
     * 게시판 통계
     */
    public function getBoardPostStats(int $boardId, bool $includeTrashed = false): array
    {
        $stats = [
            'total' => Post::ofBoard($boardId)->count(),
            'published' => Post::ofBoard($boardId)->published()->count(),
            'notices' => Post::ofBoard($boardId)->notices()->count(),
            'today' => Post::ofBoard($boardId)->whereDate('created_at', today())->count(),
        ];

        // 슈퍼관리자용: 삭제된 게시물 통계
        if ($includeTrashed) {
            $stats['trashed'] = Post::ofBoard($boardId)->onlyTrashed()->count();
        }

        return $stats;
    }

    // =========================================================================
    // File Management
    // =========================================================================

    /**
     * 파일 업로드 및 게시글 연결
     */
    public function uploadFiles(Post $post, array $files): array
    {
        $board = $post->board;
        $uploadedFiles = [];

        // 파일 첨부 허용 여부 확인
        if (! $board->allow_files) {
            throw new \Exception('이 게시판은 파일 첨부가 허용되지 않습니다.');
        }

        // 최대 파일 개수 확인
        $currentCount = $post->files()->count();
        $maxCount = $board->max_file_count;

        if ($currentCount + count($files) > $maxCount) {
            throw new \Exception("최대 {$maxCount}개의 파일만 첨부할 수 있습니다.");
        }

        $tenantId = $post->tenant_id;
        $year = now()->format('Y');
        $month = now()->format('m');
        // Path pattern: {tenant_id}/{folder_key}/{year}/{month}/{stored_name}
        // (tenant disk root already includes /tenants/)
        $basePath = "{$tenantId}/posts/{$year}/{$month}";

        foreach ($files as $file) {
            if (! $file instanceof UploadedFile) {
                continue;
            }

            // 파일 크기 확인 (KB 단위로 저장됨)
            $fileSizeKB = $file->getSize() / 1024;
            if ($fileSizeKB > $board->max_file_size) {
                $maxSizeMB = round($board->max_file_size / 1024, 1);
                throw new \Exception("파일 크기는 {$maxSizeMB}MB를 초과할 수 없습니다.");
            }

            // 저장 파일명 생성
            $storedName = Str::uuid().'.'.$file->getClientOriginalExtension();
            $filePath = "{$basePath}/{$storedName}";

            // 파일 저장
            Storage::disk('tenant')->put($filePath, file_get_contents($file));

            // DB 레코드 생성 (API 방식: document_id + document_type)
            $fileRecord = File::create([
                'tenant_id' => $tenantId,
                'is_temp' => false,
                'file_path' => $filePath,
                'display_name' => $file->getClientOriginalName(),
                'stored_name' => $storedName,
                'original_name' => $file->getClientOriginalName(),
                'file_name' => $file->getClientOriginalName(),
                'file_size' => $file->getSize(),
                'mime_type' => $file->getMimeType(),
                'file_type' => $this->getFileType($file->getMimeType()),
                'document_type' => 'post',
                'document_id' => $post->id,
                'uploaded_by' => auth()->id(),
                'created_by' => auth()->id(),
            ]);

            $uploadedFiles[] = $fileRecord;
        }

        return $uploadedFiles;
    }

    /**
     * 게시글 파일 삭제
     */
    public function deleteFile(Post $post, int $fileId): bool
    {
        $file = $post->files()->find($fileId);

        if (! $file) {
            throw new \Exception('파일을 찾을 수 없습니다.');
        }

        // 물리 파일 삭제
        if ($file->existsInStorage()) {
            Storage::disk('tenant')->delete($file->file_path);
        }

        // 소프트 삭제
        $file->deleted_by = auth()->id();
        $file->save();

        return $file->delete();
    }

    /**
     * 게시글 파일 전체 삭제 (게시글 삭제 시)
     */
    public function deleteAllFiles(Post $post): void
    {
        foreach ($post->files as $file) {
            $file->deleted_by = auth()->id();
            $file->save();
            $file->delete();
        }
    }

    /**
     * 게시글 파일 영구 삭제 (게시글 영구 삭제 시)
     */
    public function forceDeleteAllFiles(Post $post): void
    {
        foreach ($post->files()->withTrashed()->get() as $file) {
            $file->permanentDelete();
        }
    }

    /**
     * 파일 타입 추출
     */
    private function getFileType(?string $mimeType): string
    {
        if (! $mimeType) {
            return 'other';
        }

        if (str_starts_with($mimeType, 'image/')) {
            return 'image';
        }
        if (str_starts_with($mimeType, 'video/')) {
            return 'video';
        }
        if (str_starts_with($mimeType, 'audio/')) {
            return 'audio';
        }
        if (str_contains($mimeType, 'pdf')) {
            return 'pdf';
        }
        if (str_contains($mimeType, 'word') || str_contains($mimeType, 'document')) {
            return 'document';
        }
        if (str_contains($mimeType, 'excel') || str_contains($mimeType, 'spreadsheet')) {
            return 'spreadsheet';
        }
        if (str_contains($mimeType, 'zip') || str_contains($mimeType, 'rar') || str_contains($mimeType, 'compressed')) {
            return 'archive';
        }

        return 'other';
    }

    /**
     * 게시글 파일 목록 조회
     */
    public function getPostFiles(Post $post): Collection
    {
        return $post->files()->orderBy('created_at')->get();
    }

    /**
     * 파일 다운로드
     */
    public function downloadFile(Post $post, int $fileId)
    {
        $file = $post->files()->find($fileId);

        if (! $file) {
            abort(404, '파일을 찾을 수 없습니다.');
        }

        return $file->download();
    }

    /**
     * 파일 미리보기 (인라인 표시)
     */
    public function previewFile(Post $post, int $fileId)
    {
        $file = $post->files()->find($fileId);

        if (! $file) {
            abort(404, '파일을 찾을 수 없습니다.');
        }

        if (! $file->existsInStorage()) {
            abort(404, '파일을 찾을 수 없습니다.');
        }

        return response()->file($file->getStoragePath(), [
            'Content-Type' => $file->mime_type,
        ]);
    }

    // =========================================================================
    // Comment Management
    // =========================================================================

    /**
     * 게시글 댓글 목록 조회 (계층형)
     */
    public function getComments(Post $post): Collection
    {
        return $post->comments()
            ->whereNull('parent_id')
            ->with(['user', 'replies.user'])
            ->orderBy('created_at')
            ->get();
    }

    /**
     * 댓글 생성
     */
    public function createComment(Post $post, array $data): BoardComment
    {
        $data['post_id'] = $post->id;
        $data['tenant_id'] = $post->tenant_id;
        $data['user_id'] = auth()->id();
        $data['ip_address'] = request()->ip();
        $data['status'] = 'active';

        return BoardComment::create($data);
    }

    /**
     * 댓글 수정
     */
    public function updateComment(BoardComment $comment, array $data): BoardComment
    {
        $comment->update([
            'content' => $data['content'],
            'updated_by' => auth()->id(),
        ]);

        return $comment->fresh();
    }

    /**
     * 댓글 삭제 (Soft Delete)
     */
    public function deleteComment(BoardComment $comment): bool
    {
        $comment->deleted_by = auth()->id();
        $comment->save();

        return $comment->delete();
    }
}
