<?php

namespace App\Services;

use App\Models\Documents\Document;
use App\Models\Documents\DocumentApproval;
use App\Models\Documents\DocumentAttachment;
use App\Models\Documents\DocumentData;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class DocumentService extends Service
{
    // =========================================================================
    // 문서 목록/상세
    // =========================================================================

    /**
     * 문서 목록 조회
     */
    public function list(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        $query = Document::query()
            ->where('tenant_id', $tenantId)
            ->with([
                'template:id,name,category',
                'creator:id,name',
            ]);

        // 상태 필터
        if (! empty($params['status'])) {
            $query->where('status', $params['status']);
        }

        // 템플릿 필터
        if (! empty($params['template_id'])) {
            $query->where('template_id', $params['template_id']);
        }

        // 검색 (문서번호, 제목)
        if (! empty($params['search'])) {
            $search = $params['search'];
            $query->where(function ($q) use ($search) {
                $q->where('document_no', 'like', "%{$search}%")
                    ->orWhere('title', 'like', "%{$search}%");
            });
        }

        // 날짜 범위 필터
        if (! empty($params['from_date'])) {
            $query->whereDate('created_at', '>=', $params['from_date']);
        }
        if (! empty($params['to_date'])) {
            $query->whereDate('created_at', '<=', $params['to_date']);
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'created_at';
        $sortDir = $params['sort_dir'] ?? 'desc';
        $query->orderBy($sortBy, $sortDir);

        $perPage = $params['per_page'] ?? 20;

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

    /**
     * 문서 상세 조회
     */
    public function show(int $id): Document
    {
        $tenantId = $this->tenantId();

        return Document::query()
            ->where('tenant_id', $tenantId)
            ->with([
                'template:id,name,category,title',
                'template.approvalLines',
                'template.basicFields',
                'template.sections.items',
                'template.columns',
                'approvals.user:id,name',
                'data',
                'attachments.file',
                'creator:id,name',
                'updater:id,name',
            ])
            ->findOrFail($id);
    }

    // =========================================================================
    // 문서 생성/수정/삭제
    // =========================================================================

    /**
     * 문서 생성
     */
    public function create(array $data): Document
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            // 문서번호 생성
            $documentNo = $this->generateDocumentNo($tenantId, $data['template_id']);

            // 문서 생성
            $document = Document::create([
                'tenant_id' => $tenantId,
                'template_id' => $data['template_id'],
                'document_no' => $documentNo,
                'title' => $data['title'],
                'status' => Document::STATUS_DRAFT,
                'linkable_type' => $data['linkable_type'] ?? null,
                'linkable_id' => $data['linkable_id'] ?? null,
                'created_by' => $userId,
                'updated_by' => $userId,
            ]);

            // 결재선 생성
            if (! empty($data['approvers'])) {
                $this->createApprovals($document, $data['approvers'], $userId);
            }

            // 문서 데이터 저장
            if (! empty($data['data'])) {
                $this->saveDocumentData($document, $data['data']);
            }

            // 첨부파일 연결
            if (! empty($data['attachments'])) {
                $this->attachFiles($document, $data['attachments'], $userId);
            }

            return $document->fresh([
                'template:id,name,category',
                'approvals.user:id,name',
                'data',
                'attachments.file',
                'creator:id,name',
            ]);
        });
    }

    /**
     * 문서 수정
     */
    public function update(int $id, array $data): Document
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $data, $tenantId, $userId) {
            $document = Document::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            // 수정 가능 상태 확인
            if (! $document->canEdit()) {
                throw new BadRequestHttpException(__('error.document.not_editable'));
            }

            // 기본 정보 수정
            $document->fill([
                'title' => $data['title'] ?? $document->title,
                'linkable_type' => $data['linkable_type'] ?? $document->linkable_type,
                'linkable_id' => $data['linkable_id'] ?? $document->linkable_id,
                'updated_by' => $userId,
            ]);

            // 반려 상태에서 수정 시 DRAFT로 변경
            if ($document->status === Document::STATUS_REJECTED) {
                $document->status = Document::STATUS_DRAFT;
                $document->submitted_at = null;
                $document->completed_at = null;
            }

            $document->save();

            // 결재선 수정
            if (isset($data['approvers'])) {
                $document->approvals()->delete();
                if (! empty($data['approvers'])) {
                    $this->createApprovals($document, $data['approvers'], $userId);
                }
            }

            // 문서 데이터 수정
            if (isset($data['data'])) {
                $document->data()->delete();
                if (! empty($data['data'])) {
                    $this->saveDocumentData($document, $data['data']);
                }
            }

            // 첨부파일 수정
            if (isset($data['attachments'])) {
                $document->attachments()->delete();
                if (! empty($data['attachments'])) {
                    $this->attachFiles($document, $data['attachments'], $userId);
                }
            }

            return $document->fresh([
                'template:id,name,category',
                'approvals.user:id,name',
                'data',
                'attachments.file',
                'creator:id,name',
            ]);
        });
    }

    /**
     * 문서 삭제
     */
    public function destroy(int $id): bool
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $document = Document::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            // DRAFT 상태만 삭제 가능
            if ($document->status !== Document::STATUS_DRAFT) {
                throw new BadRequestHttpException(__('error.document.not_deletable'));
            }

            $document->deleted_by = $userId;
            $document->save();
            $document->delete();

            return true;
        });
    }

    // =========================================================================
    // 결재 처리
    // =========================================================================

    /**
     * 결재 요청 (DRAFT → PENDING)
     */
    public function submit(int $id): Document
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $document = Document::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            // 결재 요청 가능 상태 확인
            if (! $document->canSubmit()) {
                throw new BadRequestHttpException(__('error.document.not_submittable'));
            }

            // 결재선 존재 확인
            $approvalCount = $document->approvals()->count();
            if ($approvalCount === 0) {
                throw new BadRequestHttpException(__('error.document.approvers_required'));
            }

            $document->status = Document::STATUS_PENDING;
            $document->submitted_at = now();
            $document->updated_by = $userId;
            $document->save();

            return $document->fresh([
                'template:id,name,category',
                'approvals.user:id,name',
                'creator:id,name',
            ]);
        });
    }

    /**
     * 결재 승인
     */
    public function approve(int $id, ?string $comment = null): Document
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $comment, $tenantId, $userId) {
            $document = Document::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            // 결재 가능 상태 확인
            if (! $document->canApprove()) {
                throw new BadRequestHttpException(__('error.document.not_approvable'));
            }

            // 현재 사용자의 대기 중인 결재 단계 찾기
            $myApproval = $document->approvals()
                ->where('user_id', $userId)
                ->where('status', DocumentApproval::STATUS_PENDING)
                ->orderBy('step')
                ->first();

            if (! $myApproval) {
                throw new BadRequestHttpException(__('error.document.not_your_turn'));
            }

            // 순차 결재 확인 (이전 단계가 완료되었는지)
            $pendingBefore = $document->approvals()
                ->where('step', '<', $myApproval->step)
                ->where('status', DocumentApproval::STATUS_PENDING)
                ->exists();

            if ($pendingBefore) {
                throw new BadRequestHttpException(__('error.document.not_your_turn'));
            }

            // 승인 처리
            $myApproval->status = DocumentApproval::STATUS_APPROVED;
            $myApproval->comment = $comment;
            $myApproval->acted_at = now();
            $myApproval->updated_by = $userId;
            $myApproval->save();

            // 모든 결재 완료 확인
            $allApproved = ! $document->approvals()
                ->where('status', DocumentApproval::STATUS_PENDING)
                ->exists();

            if ($allApproved) {
                $document->status = Document::STATUS_APPROVED;
                $document->completed_at = now();
            }

            $document->updated_by = $userId;
            $document->save();

            return $document->fresh([
                'template:id,name,category',
                'approvals.user:id,name',
                'creator:id,name',
            ]);
        });
    }

    /**
     * 결재 반려
     */
    public function reject(int $id, string $comment): Document
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $comment, $tenantId, $userId) {
            $document = Document::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            // 결재 가능 상태 확인
            if (! $document->canApprove()) {
                throw new BadRequestHttpException(__('error.document.not_approvable'));
            }

            // 현재 사용자의 대기 중인 결재 단계 찾기
            $myApproval = $document->approvals()
                ->where('user_id', $userId)
                ->where('status', DocumentApproval::STATUS_PENDING)
                ->orderBy('step')
                ->first();

            if (! $myApproval) {
                throw new BadRequestHttpException(__('error.document.not_your_turn'));
            }

            // 순차 결재 확인
            $pendingBefore = $document->approvals()
                ->where('step', '<', $myApproval->step)
                ->where('status', DocumentApproval::STATUS_PENDING)
                ->exists();

            if ($pendingBefore) {
                throw new BadRequestHttpException(__('error.document.not_your_turn'));
            }

            // 반려 처리
            $myApproval->status = DocumentApproval::STATUS_REJECTED;
            $myApproval->comment = $comment;
            $myApproval->acted_at = now();
            $myApproval->updated_by = $userId;
            $myApproval->save();

            // 문서 반려 상태로 변경
            $document->status = Document::STATUS_REJECTED;
            $document->completed_at = now();
            $document->updated_by = $userId;
            $document->save();

            return $document->fresh([
                'template:id,name,category',
                'approvals.user:id,name',
                'creator:id,name',
            ]);
        });
    }

    /**
     * 결재 취소/회수 (작성자만)
     */
    public function cancel(int $id): Document
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $document = Document::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            // 취소 가능 상태 확인
            if (! $document->canCancel()) {
                throw new BadRequestHttpException(__('error.document.not_cancellable'));
            }

            // 작성자만 취소 가능
            if ($document->created_by !== $userId) {
                throw new BadRequestHttpException(__('error.document.only_creator_can_cancel'));
            }

            $document->status = Document::STATUS_CANCELLED;
            $document->completed_at = now();
            $document->updated_by = $userId;
            $document->save();

            return $document->fresh([
                'template:id,name,category',
                'creator:id,name',
            ]);
        });
    }

    // =========================================================================
    // 헬퍼 메서드
    // =========================================================================

    /**
     * 문서번호 생성
     */
    private function generateDocumentNo(int $tenantId, int $templateId): string
    {
        $prefix = 'DOC';
        $date = now()->format('Ymd');

        // 오늘 생성된 문서 중 마지막 번호 조회
        $lastNumber = Document::query()
            ->where('tenant_id', $tenantId)
            ->where('document_no', 'like', "{$prefix}-{$date}-%")
            ->orderByDesc('document_no')
            ->value('document_no');

        if ($lastNumber) {
            $sequence = (int) substr($lastNumber, -4) + 1;
        } else {
            $sequence = 1;
        }

        return sprintf('%s-%s-%04d', $prefix, $date, $sequence);
    }

    /**
     * 결재선 생성
     */
    private function createApprovals(Document $document, array $approvers, int $userId): void
    {
        foreach ($approvers as $index => $approver) {
            DocumentApproval::create([
                'document_id' => $document->id,
                'user_id' => $approver['user_id'],
                'step' => $index + 1,
                'role' => $approver['role'] ?? '승인',
                'status' => DocumentApproval::STATUS_PENDING,
                'created_by' => $userId,
                'updated_by' => $userId,
            ]);
        }
    }

    /**
     * 문서 데이터 저장
     */
    private function saveDocumentData(Document $document, array $dataItems): void
    {
        foreach ($dataItems as $item) {
            DocumentData::create([
                'document_id' => $document->id,
                'section_id' => $item['section_id'] ?? null,
                'column_id' => $item['column_id'] ?? null,
                'row_index' => $item['row_index'] ?? 0,
                'field_key' => $item['field_key'],
                'field_value' => $item['field_value'] ?? null,
            ]);
        }
    }

    /**
     * 첨부파일 연결
     */
    private function attachFiles(Document $document, array $attachments, int $userId): void
    {
        foreach ($attachments as $attachment) {
            DocumentAttachment::create([
                'document_id' => $document->id,
                'file_id' => $attachment['file_id'],
                'attachment_type' => $attachment['attachment_type'] ?? DocumentAttachment::TYPE_GENERAL,
                'description' => $attachment['description'] ?? null,
                'created_by' => $userId,
            ]);
        }
    }
}
